Railway Operation Simulator  v2.11.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
242  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
243  Attribute(0), CallingOnSet(false), Length01(Track->DefaultTrackLength), Length23(-1), SpeedLimit01(Track->DefaultTrackSpeedLimit), SpeedLimit23(-1),
244  TrainIDOnElement(-1), TrainIDOnBridgeTrackPos01(-1), TrainIDOnBridgeTrackPos23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
245  SigAspect(FourAspect)
246  {
247  for(int x = 0; x < 4; x++)
248  {
249  ConnLinkPos[x] = -1;
250  Conn[x] = -1;
251  }
252  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
253  {
256  }
257  }
258 
259 // ---------------------------------------------------------------------------
260 
261 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
262 {
263  if(lower.second < higher.second)
264  {
265  return(true);
266  }
267  else if(lower.second > higher.second)
268  {
269  return(false);
270  }
271  else if(lower.second == higher.second)
272  {
273  if(lower.first < higher.first)
274  {
275  return(true);
276  }
277  }
278  return(false);
279 }
280 
281 // ---------------------------------------------------------------------------
282 // PrefDirElement Functions
283 // ---------------------------------------------------------------------------
284 
285 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
286  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
287  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
288 {
289  if(!EntryExitNumber())
290  {
291  throw Exception("EXNumber failure in TPrefDirElement constructor");
292  }
295 }
296 
297 // ---------------------------------------------------------------------------
298 
299 AnsiString TPrefDirElement::LogPrefDir() const
300 // for debugging when passed as a call parameter
301 {
302  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
303  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
304  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
305  AnsiString(TrainIDOnBridgeTrackPos23);
306 
307 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
308  return(LogString);
309 }
310 
311 // ---------------------------------------------------------------------------
312 
313 bool TPrefDirElement::EntryExitNumber() // true for valid number
314 /*
315  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
316  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
317  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
318  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
319  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
320  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
321  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
322  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
323  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
324 */
325 
326 {
327  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
328  int EXArray[16][2] =
329  {{4, 6}, {2, 8}, // horizontal & vertical
330  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
331  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
332  {1, 9}, {3, 7}}; // forward & reverse diagonals
333 
334  int EXNum = -1;
335  int Entry, Exit;
336 
337  if(ELink > -1)
338  {
339  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
340  }
341  else if(Link[2] == -1)
342  {
343  Entry = Link[0];
344  }
345  else
346  {
347  Utilities->CallLogPop(122);
348  return(false);
349  }
350  if(XLink > -1)
351  {
352  Exit = XLink;
353  }
354  else if(Link[2] == -1)
355  {
356  Exit = Link[1];
357  }
358  else
359  {
360  Utilities->CallLogPop(123);
361  return(false);
362  }
363  for(int x = 0; x < 16; x++)
364  {
365  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
366  {
367  EXNum = x;
368  }
369  }
370  if(EXNum == -1)
371  {
372  Utilities->CallLogPop(124);
373  return(false);
374  }
375  int BrNum = -1;
376 
377 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
378  the graphic for each of which is different because of the shape of the overbridge. The basic
379  entry/exit value is computed above, and this used to select only from elements with that entry/exit
380  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
381  int BrEXArray[24][2] = {
382  {4,6},{2,8},{1,9},{3,7},
383  {1,9},{3,7},{1,9},{3,7},
384  {2,8},{4,6},{2,8},{4,6}
385 */
386 
387  if(TrackType == Bridge)
388  {
389  if(EXNum == 1)
390  {
391  if(SpeedTag == 49)
392  {
393  BrNum = 1 + 16;
394  }
395  else if(SpeedTag == 54)
396  {
397  BrNum = 8 + 16;
398  }
399  else if(SpeedTag == 55)
400  {
401  BrNum = 10 + 16;
402  }
403  }
404  else if(EXNum == 0)
405  {
406  if(SpeedTag == 48)
407  {
408  BrNum = 0 + 16;
409  }
410  else if(SpeedTag == 58)
411  {
412  BrNum = 11 + 16;
413  }
414  else if(SpeedTag == 59)
415  {
416  BrNum = 9 + 16;
417  }
418  }
419  else if(EXNum == 14)
420  {
421  if(SpeedTag == 50)
422  {
423  BrNum = 2 + 16;
424  }
425  else if(SpeedTag == 52)
426  {
427  BrNum = 4 + 16;
428  }
429  else if(SpeedTag == 57)
430  {
431  BrNum = 6 + 16;
432  }
433  }
434  else if(EXNum == 15)
435  {
436  if(SpeedTag == 51)
437  {
438  BrNum = 3 + 16;
439  }
440  else if(SpeedTag == 53)
441  {
442  BrNum = 7 + 16;
443  }
444  else if(SpeedTag == 56)
445  {
446  BrNum = 5 + 16;
447  }
448  }
449  }
450  if(BrNum == -1)
451  {
452  EXNumber = EXNum;
453  }
454  else
455  {
456  EXNumber = BrNum;
457  }
458  Utilities->CallLogPop(125);
459  return(true);
460 }
461 
462 // ---------------------------------------------------------------------------
463 
465 /*
466  This is the basic track graphic for use in plotting the original graphic during route flashing.
467  Enter with all set apart from EXGraphic & EntryDirectionGraphic
468 */
469 {
470  if(SpeedTag == 64)
471  {
472  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
473 
474  }
475  if(SpeedTag == 65)
476  {
477  return(RailGraphics->LinkGraphicsPtr[17]);
478  }
479  if(SpeedTag == 66)
480  {
481  return(RailGraphics->LinkGraphicsPtr[18]);
482  }
483  if(SpeedTag == 67)
484  {
485  return(RailGraphics->LinkGraphicsPtr[19]);
486  }
487  if(SpeedTag == 80)
488  {
489  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
490 
491  }
492  if(SpeedTag == 81)
493  {
494  return(RailGraphics->LinkGraphicsPtr[21]);
495  }
496  if(SpeedTag == 82)
497  {
498  return(RailGraphics->LinkGraphicsPtr[22]);
499  }
500  if(SpeedTag == 83)
501  {
502  return(RailGraphics->LinkGraphicsPtr[23]);
503  }
504  if(SpeedTag == 84)
505  {
506  return(RailGraphics->LinkGraphicsPtr[24]);
507  }
508  if(SpeedTag == 85)
509  {
510  return(RailGraphics->LinkGraphicsPtr[25]);
511  }
512  if(SpeedTag == 86)
513  {
514  return(RailGraphics->LinkGraphicsPtr[26]);
515  }
516  if(SpeedTag == 87)
517  {
518  return(RailGraphics->LinkGraphicsPtr[27]);
519  }
520  if(SpeedTag == 129)
521  {
522  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
523 
524  }
525  if(SpeedTag == 130)
526  {
527  return(RailGraphics->LinkGraphicsPtr[29]);
528  }
529  if(XLinkPos == -1) // not set, could be first element or last element = leading point
530  {
531 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
532 // Points & don't want to display these)
533  if(Link[2] != -1)
534  {
535  return(0); // i.e. complex element, don't display
536  }
537  else
538  {
539  if(!EntryExitNumber())
540  {
541  throw Exception("Error in EntryExitNumber 4");
542  }
543  else
544  {
546  }
547  }
548  }
549  if(EXNumber > 15) // underbridge
550  {
551  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
552  }
553  else
554  {
556  }
557 }
558 
559 // ---------------------------------------------------------------------------
560 
562 /*
563  As above but for PrefDir graphics.
564 */
565 {
566  if(SpeedTag == 64)
567  {
568  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
569 
570  }
571  if(SpeedTag == 65)
572  {
574  }
575  if(SpeedTag == 66)
576  {
578  }
579  if(SpeedTag == 67)
580  {
582  }
583  if(SpeedTag == 80)
584  {
585  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
586 
587  }
588  if(SpeedTag == 81)
589  {
591  }
592  if(SpeedTag == 82)
593  {
595  }
596  if(SpeedTag == 83)
597  {
599  }
600  if(SpeedTag == 84)
601  {
603  }
604  if(SpeedTag == 85)
605  {
607  }
608  if(SpeedTag == 86)
609  {
611  }
612  if(SpeedTag == 87)
613  {
615  }
616  if(SpeedTag == 129)
617  {
618  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
619 
620  }
621  if(SpeedTag == 130)
622  {
624  }
625  if(XLinkPos == -1) // not set, could be first element or last element = leading point
626  {
627 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
628  if(Link[2] != -1)
629  {
630  return(0); // i.e. complex element, don't display
631  }
632  else
633  {
634  if(!EntryExitNumber())
635  {
636  throw Exception("Error in EntryExitNumber 5");
637  }
638  else
639  {
641  }
642  }
643  }
644  if(EXNumber > 15) // underbridge
645  {
647  }
648  else
649  {
651  }
652 }
653 
654 // ---------------------------------------------------------------------------
655 
656 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
657 /*
658  As above but for route graphics.
659 */
660 {
661  if(!AutoSigsFlag && !PrefDirRoute)
662  {
663  if(SpeedTag == 64)
664  {
665  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
666 
667  }
668  if(SpeedTag == 65)
669  {
671  }
672  if(SpeedTag == 66)
673  {
675  }
676  if(SpeedTag == 67)
677  {
679  }
680  if(SpeedTag == 80)
681  {
682  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
683 
684  }
685  if(SpeedTag == 81)
686  {
688  }
689  if(SpeedTag == 82)
690  {
692  }
693  if(SpeedTag == 83)
694  {
696  }
697  if(SpeedTag == 84)
698  {
700  }
701  if(SpeedTag == 85)
702  {
704  }
705  if(SpeedTag == 86)
706  {
708  }
709  if(SpeedTag == 87)
710  {
712  }
713  if(SpeedTag == 129)
714  {
715  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
716 
717  }
718  if(SpeedTag == 130)
719  {
721  }
722  if(XLinkPos == -1) // not set, could be first element or last element = leading point
723  {
724  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
725  if(Link[2] != -1)
726  {
727  return(0); // i.e. complex element, don't display
728  }
729  else
730  {
731  if(!EntryExitNumber())
732  {
733  throw Exception("Error in EntryExitNumber 6");
734  }
735  else
736  {
738  }
739  }
740  }
741  if(EXNumber > 15) // underbridge
742  {
744  }
745  else
746  {
748  }
749  }
750 
751  else if(!AutoSigsFlag && PrefDirRoute)
752  {
753  if(SpeedTag == 64)
754  {
755  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
756 
757  }
758  if(SpeedTag == 65)
759  {
761  }
762  if(SpeedTag == 66)
763  {
765  }
766  if(SpeedTag == 67)
767  {
769  }
770  if(SpeedTag == 80)
771  {
772  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
773 
774  }
775  if(SpeedTag == 81)
776  {
778  }
779  if(SpeedTag == 82)
780  {
782  }
783  if(SpeedTag == 83)
784  {
786  }
787  if(SpeedTag == 84)
788  {
790  }
791  if(SpeedTag == 85)
792  {
794  }
795  if(SpeedTag == 86)
796  {
798  }
799  if(SpeedTag == 87)
800  {
802  }
803  if(SpeedTag == 129)
804  {
805  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
806 
807  }
808  if(SpeedTag == 130)
809  {
811  }
812  if(XLinkPos == -1) // not set, could be first element or last element = leading point
813  {
814  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
815  if(Link[2] != -1)
816  {
817  return(0); // i.e. complex element, don't display
818  }
819  else
820  {
821  if(!EntryExitNumber())
822  {
823  throw Exception("Error in EntryExitNumber 10");
824  }
825  else
826  {
828  }
829  }
830  }
831  if(EXNumber > 15) // underbridge
832  {
834  }
835  else
836  {
838  }
839  }
840 
841  else
842  {
843  if(SpeedTag == 64)
844  {
845  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
846 
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 // Track functions
1108 // ---------------------------------------------------------------------------
1109 
1110 // ---------------------------------------------------------------------------
1111 
1112 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1113 {
1114  TypeOfRoute = 0;
1115  ReducedTimePenalty = false;
1116  BarrierState = Up;
1117  ChangeDuration = 0.0;
1118  BaseElementSpeedTag = 1;
1119  HLoc = 0;
1120  VLoc = 0;
1121  StartTime = TDateTime(0);
1122 }
1123 
1124 // ---------------------------------------------------------------------------
1125 
1127 {
1128 // CurrentSpeedButtonTag = 0; //not assigned yet
1129 
1130  HLocMin = 2000000000;
1131  VLocMin = 2000000000;
1132  HLocMax = -2000000000;
1133  VLocMax = -2000000000;
1134  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1135  CopyFlag = false; // only true for copying, so names aren't copied
1136  AnsiString NL = '\n';
1137 
1138  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1139  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1140  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1141  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1142 
1147 
1148  int InternalLinkCheckArray[9][2] =
1149  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1150 
1151 /* array of valid link values for 'old' location and 'new' location, where
1152  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1153 
1154  for(int x = 0; x < 9; x++)
1155  {
1156  for(int y = 0; y < 2; y++)
1157  {
1158  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1159  }
1160  }
1161 
1162 // Platform and default track element values
1163  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1164 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1165  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1166  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1167  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1168  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1169  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1170  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1171  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1172  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1173 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1174 
1175  int HVArray[10][2] =
1176  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1177 
1178  for(int x = 0; x < 10; x++)
1179  {
1180  for(int y = 0; y < 2; y++)
1181  {
1182  LinkHVArray[x][y] = HVArray[x][y];
1183  }
1184  }
1185  TrackFinished = false;
1186 // DistancesSet = false;
1187 
1188  TSigElement TempSigTable[40] = // original four aspect
1189  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1190  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1191 
1192  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1193  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1194 
1197 
1198  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1199  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1200 
1201  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1202  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1203  {75, 4, RailGraphics->gl75}};
1204 
1205  for(int x = 0; x < 40; x++)
1206  {
1207  SigTable[x] = TempSigTable[x];
1208  }
1209 
1210  TSigElement TempSigTableThreeAspect[40] =
1211  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1212  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1213 
1214  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1215  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1216 
1217  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1218  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1219 
1220  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1221  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1222 
1223  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1224  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1225  {75, 4, RailGraphics->gl75}};
1226 
1227  for(int x = 0; x < 40; x++)
1228  {
1229  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1230  }
1231 
1232  TSigElement TempSigTableTwoAspect[40] =
1233  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1234  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1235 
1236  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1237  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1238 
1239  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1240  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1241 
1242  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1243  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1244 
1245  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1246  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1247  {75, 4, RailGraphics->gl75}};
1248 
1249  for(int x = 0; x < 40; x++)
1250  {
1251  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1252  }
1253 
1254  TSigElement TempSigTableGroundSignal[40] =
1258 
1262 
1266 
1270 
1271  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1274 
1275  for(int x = 0; x < 40; x++)
1276  {
1277  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1278  }
1279 
1280 /*
1281  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1282  a single location. These are as follows:-
1283  Directly Adjacent = up, down, left or right - NOT diagonal.
1284  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1285  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1286  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1287 
1288  //t 76
1289  //b 77
1290  //l 78
1291  //r 79
1292  //c 96
1293  //v fb 129
1294  //h fb 130
1295  //v underpass 145
1296  //h underpass 146
1297  //n 131
1298 */
1299 
1300  int Tag76[25][3] =
1301  {{-1, 0, 96}, // c top plat
1302  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1303  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1304  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1305  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1306  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1307  {0, 0, 129}, {0, -1, 145}, // v up
1308  {0, 0, 145}};
1309 
1310  for(int x = 0; x < 25; x++)
1311  {
1312  for(int y = 0; y < 3; y++)
1313  {
1314  Tag76Array[x][y] = Tag76[x][y];
1315  }
1316  }
1317 
1318  int Tag77[25][3] =
1319  {{-1, 0, 96}, // c bot plat
1320  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1321  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1322  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1323  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1324  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1325  {0, 0, 129}, {0, 1, 145}, // v up
1326  {0, 0, 145}};
1327 
1328  for(int x = 0; x < 25; x++)
1329  {
1330  for(int y = 0; y < 3; y++)
1331  {
1332  Tag77Array[x][y] = Tag77[x][y];
1333  }
1334  }
1335 
1336  int Tag78[25][3] =
1337  {{-1, 0, 96}, // c left plat
1338  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1339  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1340  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1341  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1342  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1343  {0, 0, 130}, {-1, 0, 146}, // h up
1344  {0, 0, 146}};
1345 
1346  for(int x = 0; x < 25; x++)
1347  {
1348  for(int y = 0; y < 3; y++)
1349  {
1350  Tag78Array[x][y] = Tag78[x][y];
1351  }
1352  }
1353 
1354  int Tag79[25][3] =
1355  {{-1, 0, 96}, // c right plat
1356  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1357  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1358  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1359  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1360  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1361  {0, 0, 130}, {1, 0, 146}, // h up
1362  {0, 0, 146}};
1363 
1364  for(int x = 0; x < 25; x++)
1365  {
1366  for(int y = 0; y < 3; y++)
1367  {
1368  Tag79Array[x][y] = Tag79[x][y];
1369  }
1370  }
1371 
1372  int Tag96[28][3] =
1373  {{-1, 0, 96}, // c //concourse
1374  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1375  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1376  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1377  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1378  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1379  {0, -1, 129}, {1, 0, 130}, // h fb
1380  {-1, 0, 130}, {0, 1, 145}, // v up
1381  {0, -1, 145}, {1, 0, 146}, // h up
1382  {-1, 0, 146}};
1383 
1384  for(int x = 0; x < 28; x++)
1385  {
1386  for(int y = 0; y < 3; y++)
1387  {
1388  Tag96Array[x][y] = Tag96[x][y];
1389  }
1390  }
1391 
1392  int Tag129[8][3] = // vert fb
1393  {{0, -1, 96}, // c
1394  {0, -1, 77}, // b
1395  {0, -1, 129}, // v fb
1396 
1397  {0, 1, 96}, // c
1398  {0, 1, 76}, // t
1399  {0, 1, 129}, // v fb
1400 
1401  {0, 0, 76}, // t
1402  {0, 0, 77}}; // b
1403 
1404  for(int x = 0; x < 8; x++)
1405  {
1406  for(int y = 0; y < 3; y++)
1407  {
1408  Tag129Array[x][y] = Tag129[x][y];
1409  }
1410  }
1411 
1412  int Tag145[8][3] = // vert up
1413  {{0, -1, 96}, // c
1414  {0, -1, 77}, // b
1415  {0, -1, 145}, // v fb
1416 
1417  {0, 1, 96}, // c
1418  {0, 1, 76}, // t
1419  {0, 1, 145}, // v fb
1420 
1421  {0, 0, 76}, // t
1422  {0, 0, 77}}; // b
1423 
1424  for(int x = 0; x < 8; x++)
1425  {
1426  for(int y = 0; y < 3; y++)
1427  {
1428  Tag145Array[x][y] = Tag145[x][y];
1429  }
1430  }
1431 
1432  int Tag130[8][3] = // hor fb
1433  {{-1, 0, 96}, // c
1434  {-1, 0, 79}, // r
1435  {-1, 0, 130}, // h fb
1436 
1437  {1, 0, 96}, // c
1438  {1, 0, 78}, // l
1439  {1, 0, 130}, // h fb
1440 
1441  {0, 0, 78}, // l
1442  {0, 0, 79}}; // r
1443 
1444  for(int x = 0; x < 8; x++)
1445  {
1446  for(int y = 0; y < 3; y++)
1447  {
1448  Tag130Array[x][y] = Tag130[x][y];
1449  }
1450  }
1451 
1452  int Tag146[8][3] = // hor up
1453  {{-1, 0, 96}, // c
1454  {-1, 0, 79}, // r
1455  {-1, 0, 146}, // h fb
1456 
1457  {1, 0, 96}, // c
1458  {1, 0, 78}, // l
1459  {1, 0, 146}, // h fb
1460 
1461  {0, 0, 78}, // l
1462  {0, 0, 79}}; // r
1463 
1464  for(int x = 0; x < 8; x++)
1465  {
1466  for(int y = 0; y < 3; y++)
1467  {
1468  Tag146Array[x][y] = Tag146[x][y];
1469  }
1470  }
1471 
1472  int Tag131[4][3] =
1473  {{-1, 0, 131}, // n
1474  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1475 
1476  for(int x = 0; x < 4; x++)
1477  {
1478  for(int y = 0; y < 3; y++)
1479  {
1480  Tag131Array[x][y] = Tag131[x][y];
1481  }
1482  }
1483 
1484  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1485  {
1486  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1487  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1488  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1489  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1490  140, 144, 145, 146
1491  };
1492 
1493  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1494  {
1495  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1496  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1497  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1498  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1499  141, 144, 145, 146
1500  };
1501 
1502  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1503  {
1504  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1505  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1506  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1507  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1508  141, 144, 146, 145
1509  };
1510 
1511  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1512  {
1513  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1514  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1515  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1516  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1517  140, 144, 146, 145
1518  };
1519 
1520  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1521  {
1522  FlipArray[x] = InternalFlipArray[x];
1523  MirrorArray[x] = InternalMirrorArray[x];
1524  RotRightArray[x] = InternalRotRightArray[x];
1525  RotLeftArray[x] = InternalRotLeftArray[x];
1526  }
1527 }
1528 
1529 // ---------------------------------------------------------------------------
1531 {
1532 // delete TrackVectorPtr;
1533 // delete FixedTrackArrayPtr;
1534  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1535 
1536  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1537  {
1538  delete UGMIt->second;
1539  UGMIt++;
1540  }
1541  delete GapFlashGreen;
1542  delete GapFlashRed;
1543  // all the rest are cleared by the relevant automatic destructors
1544 }
1545 
1546 // ---------------------------------------------------------------------------
1547 
1549 {
1550  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1551  {
1552 // loc 0 not used, set to bmSolidBgnd
1556 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1576  };
1577 
1578  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1579  {
1580 // loc 0 not used, set to smSolidBgnd
1584 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1603  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1604  };
1605 
1606 // track types
1607  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1608  {
1609  Erase, // 1 0
1610  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1611  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1612  Crossover, Crossover, // 2 15-16
1613  Unused, // 17 (was for text in earlier development) //1 17
1616  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1620  Platform, Platform, Platform, Platform, // 4 76-79
1623  Concourse, // 1 96
1626  Simple, Simple, Simple, Simple, // 4 125-128
1627  FootCrossing, FootCrossing, // 2 129-130
1628  NamedNonStationLocation, // 1 131
1629  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1630  Simple, Simple, Simple, Simple, // 4 140-143
1631  LevelCrossing, // 1 144
1632  FootCrossing, FootCrossing // 2 145 & 146
1633  };
1634 
1635 // links
1636  int Links[FirstUnusedSpeedTagNumber][4] =
1637  {{-1, -1, -1, -1}, // erase element
1638  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1639  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1640 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1641  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1642  {-1, -1, -1, -1}, // unused
1643  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1644  {2, 7, -1, -1}, // simple
1645  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1646 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1647 // (or right diverging if no straight)
1648  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1649  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1650  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1651  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1652  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1653  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1654  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1655  {-1, -1, -1, -1}, // Concourse
1656  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1657  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1658  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1659  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1660  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1661  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1662  {-1, -1, -1, -1}, // NamedNonStationLocation
1663  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1664 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1665  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1666  {-1, -1, -1, -1}, // level crossing
1667  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1668  };
1669 
1671  {{NotSet, NotSet, NotSet, NotSet}, // unused
1675  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1677  {NotSet, NotSet, NotSet, NotSet}, // unused
1681  {Connection, Connection, NotSet, NotSet}, // simple
1685  {Lead, Trail, Lead, Trail}, // points
1687  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1695  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1701  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1710  {Connection, Connection, NotSet, NotSet}, // Arrows
1712  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1714  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1716  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1717  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1718  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1719  };
1720 
1721  for(int x = 0; x < 17; x++)
1722  {
1723  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1724  }
1725  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1726 // 17 was the old text value so don't want any graphics (now disused)
1727  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1728  {
1729  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1730  }
1731 }
1732 
1733 // ---------------------------------------------------------------------------
1734 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1735  ExistingGraphicLoaded(false), Width(16), Height(16)
1736 {
1737  OriginalGraphic = new Graphics::TBitmap;
1738  OriginalGraphic->PixelFormat = pf8bit;
1739  OriginalGraphic->Width = Width;
1740  OriginalGraphic->Height = Height;
1741  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1742 }
1743 
1744 // ---------------------------------------------------------------------------
1745 
1746 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1747  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1748 {
1749  OriginalGraphic = new Graphics::TBitmap;
1750  OriginalGraphic->PixelFormat = pf8bit;
1751  OriginalGraphic->Width = Width;
1752  OriginalGraphic->Height = Height;
1753  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1754 }
1755 
1756 // ---------------------------------------------------------------------------
1757 
1759 {
1760  delete OriginalGraphic;
1761 }
1762 
1763 // ---------------------------------------------------------------------------
1764 
1765 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1766 {
1767  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1768  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1769  VPos = VPosIn;
1770  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1771 
1772  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1773  SourceRect.init(Left, Top, Left + Width, Top + Height);
1774  ScreenSourceSet = true;
1775  Utilities->CallLogPop(422);
1776 }
1777 
1778 // ---------------------------------------------------------------------------
1779 
1781 {
1782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1783  if(!OverlayLoaded)
1784  {
1785  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1786  }
1787  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1788  {
1789  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1790  }
1791  if(!ScreenSourceSet)
1792  {
1793  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1794  }
1795  if(ExistingGraphicLoaded) // can only call one of the load functions
1796  {
1797  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1798  }
1799  if(OverlayPlotted) // don't load from screen if overlay plotted
1800  {
1801  Utilities->CallLogPop(775);
1802  return;
1803  }
1804  TRect DestRect(0, 0, Width, Height);
1805 
1807  OriginalLoaded = true;
1808  ScreenGraphicLoaded = true;
1809  Utilities->CallLogPop(423);
1810 }
1811 
1812 // ---------------------------------------------------------------------------
1813 
1814 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1815 /*
1816  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1817 */
1818 {
1819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1820  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1821  if(!OverlayLoaded)
1822  {
1823  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1824  }
1825  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1826  {
1827  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1828  }
1829  if(ScreenGraphicLoaded) // can only call one of the load functions
1830  {
1831  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1832  }
1833  Width = WidthIn;
1834  Height = HeightIn;
1835  OriginalGraphic->Width = Width;
1836  OriginalGraphic->Height = Height;
1837  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1838  VPos += VOffset;
1839  TRect DestRect(0, 0, Width, Height);
1840 
1841  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1842  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1843  OriginalLoaded = true;
1844  ExistingGraphicLoaded = true;
1845  Utilities->CallLogPop(424);
1846 }
1847 
1848 // ---------------------------------------------------------------------------
1849 
1850 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1851 {
1852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1853  OverlayGraphic = Overlay;
1854  OverlayLoaded = true;
1855  Utilities->CallLogPop(425);
1856 }
1857 
1858 // ---------------------------------------------------------------------------
1859 
1861 {
1862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1863  if(!OverlayLoaded)
1864  {
1865  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1866  }
1867  if(!OverlayPlotted)
1868  {
1869  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1870  Disp->Update();
1871  OverlayPlotted = true;
1872  }
1873  Utilities->CallLogPop(426);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1881  if(OverlayPlotted)
1882  {
1883  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1884  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1885  {
1886  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1887  }
1888  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1889  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1890  OverlayPlotted = false;
1891  }
1892  Utilities->CallLogPop(427);
1893 }
1894 
1895 // ---------------------------------------------------------------------------
1896 
1898 {
1899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1900  bool TrackPresent = false;
1901 
1902  if(InactiveTrackVector.size() != 0)
1903  {
1904  Utilities->CallLogPop(1333);
1905  return(false);
1906  }
1907  else if(TrackVector.size() == 0)
1908  {
1909  Utilities->CallLogPop(1334);
1910  return(true);
1911  }
1912  else
1913  {
1914  for(unsigned int x = 0; x < TrackVector.size(); x++)
1915  {
1916  if((TrackElementAt(1042, x).SpeedTag != 0))
1917  {
1918  TrackPresent = true;
1919  }
1920  }
1921  }
1922  Utilities->CallLogPop(1335);
1923  return(!TrackPresent);
1924 }
1925 
1926 // ---------------------------------------------------------------------------
1927 
1928 bool TTrack::NoActiveTrack(int Caller)
1929 {
1930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1931  bool TrackPresent = false;
1932 
1933  if(TrackVector.size() == 0)
1934  {
1935  Utilities->CallLogPop(1582);
1936  return(true);
1937  }
1938  else
1939  {
1940  for(unsigned int x = 0; x < TrackVector.size(); x++)
1941  {
1942  if((TrackElementAt(1043, x).SpeedTag != 0))
1943  {
1944  TrackPresent = true;
1945  }
1946  break;
1947  }
1948  }
1949  Utilities->CallLogPop(1583);
1950  return(!TrackPresent);
1951 }
1952 
1953 // ---------------------------------------------------------------------------
1954 
1955 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1956 {
1957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1958  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1959  TrackEraseSuccessfulFlag = false;
1960 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1961 // since have to match platforms as well as track
1962 // used to set TrackFinished to false if an element erased
1963 
1964  ErasedTrackVectorPosition = -1; // marker for no element erased
1965  AnsiString SName = "", ErrorString;
1967  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1968  TTrackMapIterator TrackMapPtr;
1969  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1970 
1971  if(TrackVector.size() != 0)
1972  {
1973  TrackMapKeyPair.first = HLocInput;
1974  TrackMapKeyPair.second = VLocInput;
1975  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1976  if(TrackMapPtr != TrackMap.end())
1977  {
1978  bool FoundFlag;
1979  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1980  if(FoundFlag) // should find it as it's in the map
1981  {
1982  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1983  {
1984  SName = TrackElementAt(1, VecPos).LocationName;
1985  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1986  if(ErrorString != "")
1987  {
1988  throw Exception(ErrorString + " for EraseTrackElement 1");
1989  }
1990  LocationNameMultiMap.erase(SNIt);
1991  }
1992  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1993  // ensure erase vector element before map element as iterator no longer valid after a map erase
1994  TrackMap.erase(TrackMapPtr);
1995  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1996  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1998  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1999  if(SName != "")
2000  {
2001  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2002  int HPos, VPos;
2003  if(TextHandler->FindText(1, SName, HPos, VPos))
2004  {
2005  if(TextHandler->TextErase(5, HPos, VPos, SName))
2006  {
2007  ;
2008  } // condition not used
2009 
2010  }
2011  }
2012  ErasedTrackVectorPosition = VecPos;
2013  TrackEraseSuccessfulFlag = true;
2014  }
2015  }
2016  }
2017  if(InactiveTrackVector.size() != 0)
2018  {
2019  unsigned int VecPos;
2020  InactiveTrackMapKeyPair.first = HLocInput;
2021  InactiveTrackMapKeyPair.second = VLocInput;
2022  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2023  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2024  {
2025  SName = "";
2026  VecPos = InactiveTrack2MultiMapIterator->second;
2027  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2028  {
2029  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2030  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2031  if(ErrorString != "")
2032  {
2033  throw Exception(ErrorString + " for EraseTrackElement 2A");
2034  }
2035  LocationNameMultiMap.erase(SNIt);
2036  }
2037  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2038  // ensure erase vector element before map element as iterator no longer valid after a map erase
2039  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2040  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2041  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2043  TrackEraseSuccessfulFlag = true;
2044  if(SName != "")
2045  {
2046  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2047  int HPos, VPos;
2048  if(TextHandler->FindText(2, SName, HPos, VPos))
2049  {
2050  if(TextHandler->TextErase(6, HPos, VPos, SName))
2051  {
2052  ;
2053  } // condition not used
2054 
2055  }
2056  }
2057  }
2058  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2059  {
2060  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2061  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2062  {
2063  SName = "";
2064  VecPos = InactiveTrack2MultiMapIterator->second;
2065  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2066  {
2067  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2068  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2069  if(ErrorString != "")
2070  {
2071  throw Exception(ErrorString + " for EraseTrackElement 2B");
2072  }
2073  LocationNameMultiMap.erase(SNIt);
2074  }
2075  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2076  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2077  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2079  if(SName != "")
2080  {
2081  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2082  int HPos, VPos;
2083  if(TextHandler->FindText(3, SName, HPos, VPos))
2084  {
2085  if(TextHandler->TextErase(7, HPos, VPos, SName))
2086  {
2087  ;
2088  } // condition not used
2089 
2090  }
2091  }
2092  }
2093  }
2094  }
2095  if(TrackEraseSuccessfulFlag)
2096  {
2097  CalcHLocMinEtc(2);
2098  SetTrackFinished(false);
2099  }
2100  if(InternalChecks)
2101  {
2102  CheckMapAndTrack(1); // test
2103  CheckMapAndInactiveTrack(1); // test
2104  CheckLocationNameMultiMap(6); // test
2105  }
2106  Utilities->CallLogPop(428);
2107 }
2108 
2109 // ---------------------------------------------------------------------------
2110 
2111 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2112 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2113 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2114 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2115 {
2116  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2117  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2118  bool PlatAllowedFlag = false;
2119 
2120  TrackLinkingRequiredFlag = false;
2121 /*
2122  Not erase, that covered separately.
2123  First check if Current SpeedButton assigned, then check if a platform and only
2124  permit if an appropriate trackpiece already there & not a same platform there.
2125  - can't enter a platform without track first.
2126  Then for non-platforms, check if a track piece already present at location &
2127  reject if so.
2128 */
2129 
2130  TLocationNameMultiMapEntry LocationNameEntry;
2131 
2132  LocationNameEntry.first = "";
2133  if(CurrentTag == 0)
2134  {
2135  Utilities->CallLogPop(429);
2136  return; // not assigned yet
2137  }
2138  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2139 
2140  TempTrackElement.HLoc = HLocInput;
2141  TempTrackElement.VLoc = VLocInput;
2142  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2143 // new at version 0.6 - set signal aspect depending on build mode
2144 
2145  if(TempTrackElement.TrackType == SignalPost)
2146  {
2147  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2148  // pasting a SignalPost can only have values 1 to 4
2149  {
2151  {
2152  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2153  }
2155  {
2156  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2157  }
2159  {
2160  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2161  }
2162  else
2163  {
2164  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2165  }
2166  }
2167  else if(Aspect == 1)
2168  {
2169  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2170  }
2171  else if(Aspect == 2)
2172  {
2173  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2174  }
2175  else if(Aspect == 3)
2176  {
2177  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2178  }
2179  else
2180  {
2181  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2182  }
2183  }
2184  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2185  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2186  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2187  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2188 
2189  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2190  {
2192  {
2193  NonStationOrLevelCrossingPresent = true;
2194  }
2195  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2196  {
2197  NonStationOrLevelCrossingPresent = true;
2198  }
2199  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2200  {
2201  PlatformPresent = true;
2202  }
2203  // no need to check IMPair.second since if that exists it is because .first is a platform
2204  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2205  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2206  }
2207 // check platforms
2208  if(TempTrackElement.TrackType == Platform)
2209  {
2210  if(FoundFlag) // active track element already there
2211  {
2212  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2213  {
2214  ;
2215  }
2216  // same platform type already there so above keeps PlatAllowedFlag false
2217  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2218  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2219  {
2220  PlatAllowedFlag = true;
2221  }
2222  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2223  {
2224  PlatAllowedFlag = true;
2225  }
2226  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2227  {
2228  PlatAllowedFlag = true;
2229  }
2230  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2231  {
2232  PlatAllowedFlag = true;
2233  }
2234  if(PlatAllowedFlag)
2235  {
2236  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2237  TrackPush(1, TempTrackElement);
2238  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2239  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2240  // Must be called AFTER TrackPush
2241  // No need to plot the element - Clearand ... called after this function called
2242  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2243  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2244 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2245 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2246 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2247  if(InternalChecks)
2248  {
2249  CheckMapAndInactiveTrack(5); // test
2250  CheckLocationNameMultiMap(4); // test
2251  }
2252  Utilities->CallLogPop(430);
2253  return;
2254  }
2255  } // if(FoundFlag)
2256 
2257  Utilities->CallLogPop(431);
2258  return;
2259  } // if platform
2260 
2261 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2262  if(TempTrackElement.TrackType == NamedNonStationLocation)
2263  {
2264  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2265  (!FoundFlag && !InactiveFoundFlag))
2266  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2267  {
2268  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2269  TrackPush(2, TempTrackElement);
2270  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2271  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2272  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2273  {
2274 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2275 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2276 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2277  }
2278  if(InternalChecks)
2279  {
2280  CheckMapAndInactiveTrack(11); // test
2281  CheckLocationNameMultiMap(12); // test
2282  }
2283  Utilities->CallLogPop(432);
2284  return;
2285  }
2286  else
2287  {
2288  Utilities->CallLogPop(433);
2289  return;
2290  }
2291  }
2292 // check if a level crossing - OK if placed on a plain straight track
2293  if(TempTrackElement.TrackType == LevelCrossing)
2294  {
2295  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2296  {
2297  TrackPush(11, TempTrackElement);
2298  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2299 // no need for reference to LC element as can't be open
2300  TrackLinkingRequiredFlag = true;
2301  Utilities->CallLogPop(1907);
2302  return;
2303  }
2304  else
2305  {
2306  Utilities->CallLogPop(1906);
2307  return; // was a level crossing but can't place it for some reason
2308  }
2309  }
2310 
2311 // check if another element already there
2312  else if(FoundFlag || InactiveFoundFlag)
2313  {
2314  Utilities->CallLogPop(434);
2315  return; // something already there (active or inactive track)
2316  }
2317 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2318 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2319 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2320 // do this after pushed into vector so that can use EnterLocationName
2321 
2322  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2323  {
2324  TrackPush(3, TempTrackElement);
2325  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2326  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2327  }
2328  else if(TempTrackElement.TrackType == Points)
2329  {
2330  TrackPush(4, TempTrackElement);
2331  bool BothPointFillets = true;
2332  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2333  }
2334  else if(TempTrackElement.TrackType == SignalPost)
2335  {
2336  TrackPush(10, TempTrackElement);
2337  PlotSignal(12, TempTrackElement, Display);
2338  }
2339  else
2340  {
2341  TrackPush(5, TempTrackElement);
2342  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2343  }
2344  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2345  {
2346  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2347  }
2348  if(InternalChecks)
2349  {
2350  CheckMapAndTrack(2); // test
2351  CheckMapAndInactiveTrack(2); // test
2352  CheckLocationNameMultiMap(5); // test
2353  }
2354  Utilities->CallLogPop(2062);
2355 }
2356 
2357 // ---------------------------------------------------------------------------
2358 
2359 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2360  bool InternalChecks)
2361 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2362 {
2363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2364  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2365  bool PlatAllowedFlag = false;
2366 
2367  TrackLinkingRequiredFlag = false;
2368  TLocationNameMultiMapEntry LocationNameEntry;
2369 
2370  LocationNameEntry.first = "";
2371  if(TempTrackElement.SpeedTag == 0)
2372  {
2373  Utilities->CallLogPop(2063);
2374  return; // not assigned yet
2375  }
2376  TempTrackElement.HLoc = HLocInput;
2377  TempTrackElement.VLoc = VLocInput;
2378  for(int x = 0; x < 4; x++) // unset any gaps
2379  {
2380  if(TempTrackElement.Config[x] == Gap)
2381  {
2382  TempTrackElement.ConnLinkPos[x] = -1;
2383  }
2384  TempTrackElement.Conn[x] = -1;
2385  }
2386  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2387 // new at version 0.6 - set signal aspect depending on build mode
2388  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2389  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2390 
2391  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2392  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2393  // for the active track element because these aren't set
2394  // if don't do this then get a mismatch error during map checks later
2395 
2396  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2397 
2398  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2399  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2400 
2401  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2402  {
2403  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2404  {
2405  NonStationOrLevelCrossingPresent = true;
2406  }
2407  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2408  {
2409  NonStationOrLevelCrossingPresent = true;
2410  }
2411  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2412  {
2413  PlatformPresent = true;
2414  }
2415  // no need to check IMPair.second since if that exists it is because .first is a platform
2416  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2417  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2418  }
2419 // check platforms
2420  if(TempTrackElement.TrackType == Platform)
2421  {
2422  if(FoundFlag) // active track element already there
2423  {
2424  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2425  {
2426  ;
2427  }
2428  // same platform type already there so above keeps PlatAllowedFlag false
2429  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2430  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2431  {
2432  PlatAllowedFlag = true;
2433  }
2434  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2435  {
2436  PlatAllowedFlag = true;
2437  }
2438  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2439  {
2440  PlatAllowedFlag = true;
2441  }
2442  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2443  {
2444  PlatAllowedFlag = true;
2445  }
2446  if(PlatAllowedFlag)
2447  {
2448  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2449  TrackPush(12, TempTrackElement);
2450 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2451  {
2452  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2453  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2454  }
2455  // Must be called AFTER TrackPush
2456 // No need to plot the element - Clearand ... called after this function called
2457  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2458  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2459 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2460 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2461 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2462  if(InternalChecks)
2463  {
2464  CheckMapAndInactiveTrack(12); // test
2465  CheckLocationNameMultiMap(20); // test
2466  }
2467  Utilities->CallLogPop(2064);
2468  return;
2469  }
2470  } // if(FoundFlag)
2471 
2472  Utilities->CallLogPop(2065);
2473  return;
2474  } // if platform
2475 
2476 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2477  if(TempTrackElement.TrackType == NamedNonStationLocation)
2478  {
2479  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2480  (!FoundFlag && !InactiveFoundFlag))
2481  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2482  {
2483  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2484  TrackPush(13, TempTrackElement);
2485 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2486  {
2487  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2488  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2489  }
2490  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2491  {
2492 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2493 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2494 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2495  }
2496  if(InternalChecks)
2497  {
2498  CheckMapAndInactiveTrack(13); // test
2499  CheckLocationNameMultiMap(21); // test
2500  }
2501  Utilities->CallLogPop(2066);
2502  return;
2503  }
2504  else
2505  {
2506  Utilities->CallLogPop(2067);
2507  return;
2508  }
2509  }
2510 // check if a level crossing - OK if placed on a plain straight track
2511  if(TempTrackElement.TrackType == LevelCrossing)
2512  {
2513  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2514  {
2515  TrackPush(14, TempTrackElement);
2516  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2517 // no need for reference to LC element as can't be open
2518  TrackLinkingRequiredFlag = true;
2519  Utilities->CallLogPop(2068);
2520  return;
2521  }
2522  else
2523  {
2524  Utilities->CallLogPop(2069);
2525  return; // was a level crossing but can't place it for some reason
2526  }
2527  }
2528 
2529 // check if another element already there
2530  else if(FoundFlag || InactiveFoundFlag)
2531  {
2532  Utilities->CallLogPop(2070);
2533  return; // something already there (active or inactive track)
2534  }
2535 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2536 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2537 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2538 // do this after pushed into vector so that can use EnterLocationName
2539 
2540  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2541  {
2542  TrackPush(15, TempTrackElement);
2543  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2544  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2545  }
2546  else if(TempTrackElement.TrackType == Points)
2547  {
2548  TrackPush(16, TempTrackElement);
2549  bool BothPointFillets = true;
2550  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2551  }
2552  else if(TempTrackElement.TrackType == SignalPost)
2553  {
2554  TrackPush(17, TempTrackElement);
2555  PlotSignal(14, TempTrackElement, Display);
2556  }
2557  else
2558  {
2559  TrackPush(18, TempTrackElement);
2560  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2561  }
2562  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2563  {
2564  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2565  }
2566  if(InternalChecks)
2567  {
2568  CheckMapAndTrack(12); // test
2569  CheckMapAndInactiveTrack(14); // test
2570  CheckLocationNameMultiMap(22); // test
2571  }
2572  Utilities->CallLogPop(2071);
2573 }
2574 
2575 // ---------------------------------------------------------------------------
2576 
2577 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2578 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2579 // return bool = true for success
2580 // LocError = true for location error & HLoc & VLoc to be inverted
2581 {
2582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2583  LocError = false;
2584  SetTrackFinished(false);
2585  if(TrackVector.size() == 0)
2586  {
2587  Utilities->CallLogPop(437);
2588  return(false);
2589  }
2590  if(GapsUnset(7))
2591  {
2592  if(GiveMessages)
2593  {
2594  ShowMessage("Gaps must be set before track can be validated");
2595  }
2596  Utilities->CallLogPop(1135);
2597  return(false);
2598  }
2599 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2600 // returns true for any unset gaps
2602  {
2603  // can keep this exception as protected by the GapsUnset call above
2604  throw Exception("Error, gaps unset when TryToConnectTrack called");
2605  }
2607  CheckGapMap(1); // test
2608 // Gap connections now securely defined
2609 
2610  CheckMapAndTrack(8); // test
2611 
2612 // Perform a pre-check prior to TrackMap being compiled
2613  if(GiveMessages)
2614  {
2615  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2616  {
2617  Utilities->CallLogPop(439);
2618  return(false);
2619  }
2620  }
2621  else
2622  {
2623  if(!LinkTrackNoMessages(1, false))
2624  {
2625  Utilities->CallLogPop(1131);
2626  return(false);
2627  }
2628  }
2629 // here if pre-check successful
2630  if(!RepositionAndMapTrack(0))
2631  {
2632  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2633  Utilities->CallLogPop(1138);
2634  return(false);
2635  }
2636 // now perform the final assembly - FinalCall = true
2637  if(GiveMessages)
2638  {
2639  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2640  {
2641  Utilities->CallLogPop(1116);
2642  return(false);
2643  }
2644  }
2645  else
2646  {
2647  if(!LinkTrackNoMessages(2, true))
2648  {
2649  Utilities->CallLogPop(1132);
2650  return(false);
2651  }
2652  }
2653 // success
2654 
2655  PopulateLCVector(0);
2656  CheckGapMap(2); // test
2657  CheckMapAndTrack(3); // test
2658  CheckMapAndInactiveTrack(3); // test
2659  CheckLocationNameMultiMap(9); // test
2660  SetTrackFinished(true);
2661 
2662 // Build ContinuationNameMap
2663  std::pair<AnsiString, char>TempMapPair;
2664 
2665  ContinuationNameMap.clear();
2666  for(int x = 0; x < Track->TrackVectorSize(); x++)
2667  {
2668  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2669  {
2670  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2671  TempMapPair.second = 'x'; // unused
2672  ContinuationNameMap.insert(TempMapPair);
2673  }
2674  }
2675 
2676 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2677 //(don't report blue areas without track as these unlikely to be mistakes)
2678 
2679  if(TrackFinished)
2680  {
2681  AnsiString Name = "";
2682  typedef std::list<AnsiString> TNoPlatsList;
2683  TNoPlatsList::iterator NPLIt;
2684  TNoPlatsList NoPlatsList;
2685  typedef std::list<AnsiString> TLocNameList;
2686  TLocNameList LocNameList; //single entry for each name
2689  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2690  {
2691  LocNameList.push_back(LNMMIt->first);
2692  }
2693  LocNameList.sort();
2694  LocNameList.unique();
2695  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2696  {
2697  Name = *LNLIt;
2698  MMRange = LocationNameMultiMap.equal_range(Name);
2699  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2700  {
2701  continue;
2702  }
2703  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2704  {
2705  if((LNMMIt->second) < 0) //active track element
2706  {
2707  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2708  {
2709  break;
2710  }
2711  }
2712  else //inactive
2713  {
2714  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2715  {
2716  break;
2717  }
2718  }
2719  TempIt = MMRange.second;
2720  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2721  {
2722  NoPlatsList.push_back(Name);
2723  }
2724  }
2725  }
2726  if(!NoPlatsList.empty())
2727  {
2728  AnsiString NoPlatsAnsiList = "";
2729  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2730  {
2731  NoPlatsAnsiList += *NPLIt + '\n';
2732  }
2733  if(!NoPlatsMessageSent)
2734  {
2735  if(NoPlatsList.size() > 1)
2736  {
2737  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2738  }
2739  else
2740  {
2741  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2742  }
2743  NoPlatsMessageSent = true;
2744  }
2745  }
2746  }
2747  Utilities->CallLogPop(440);
2748  return(true);
2749 }
2750 
2751 // ---------------------------------------------------------------------------
2752 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2753 // unused - too time-consuming - double brute force search
2754 {
2755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2756  int NewHLoc, NewVLoc;
2757  bool ConnectionFoundFlag, LinkFoundFlag;
2758 
2759  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2760  {
2761  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2762  {
2763  if(TrackElementAt(1061, x).Link[y] <= 0)
2764  {
2765  continue; // no link
2766  }
2767  if(TrackElementAt(1062, x).Config[y] == End)
2768  {
2769  continue; // buffer or continuation
2770  }
2771  if(TrackElementAt(1063, x).Config[y] == Gap)
2772  {
2773  continue; // gap jump
2774  }
2775  // get required H & V for track element joining link 'y'
2776  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2777  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2778  // find track element if present
2779  ConnectionFoundFlag = false;
2780  for(unsigned int z = 0; z < TrackVector.size(); z++)
2781  {
2782 // if(TrackElementAt(5, z).TrackType == Platform)
2783 // continue; //skip platforms
2784  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2785  {
2786  ConnectionFoundFlag = true;
2787  // find connecting link in the newly found track element if there is one
2788  LinkFoundFlag = false;
2789  for(unsigned int a = 0; a < 4; a++)
2790  {
2791  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2792  {
2793  LinkFoundFlag = true;
2794  }
2795  }
2796  // if there isn't a corresponding link set the invert values for the offending element
2797  if(!LinkFoundFlag)
2798  {
2799  HLoc = TrackElementAt(1072, x).HLoc;
2800  VLoc = TrackElementAt(1073, x).VLoc;
2801  Utilities->CallLogPop(441);
2802  return(true);
2803  }
2804  break; // success, so break out of 'z' loop
2805  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2806 
2807  } // for z...
2808  // if there isn't a connection set the invert values for the offending element
2809  if(!ConnectionFoundFlag)
2810  {
2811  HLoc = TrackElementAt(1074, x).HLoc;
2812  VLoc = TrackElementAt(1075, x).VLoc;
2813  Utilities->CallLogPop(442);
2814  return(true);
2815  }
2816  } // for y....
2817  } // for x...
2818  Utilities->CallLogPop(443);
2819  return(false); // all OK
2820 }
2821 
2822 // ---------------------------------------------------------------------------
2823 
2824 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2825 {
2826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2827  TrackElement.LogTrack(0));
2828  bool FoundFlag;
2829 
2830  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2831  if(FoundFlag)
2832  {
2833  TrackElement = TrackElementAt(1076, Position);
2834  }
2835  Utilities->CallLogPop(444);
2836  return(FoundFlag);
2837 }
2838 
2839 // ---------------------------------------------------------------------------
2840 
2842 {
2843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2844  if(NextTrackElementPtr >= TrackVector.end())
2845  {
2846  Utilities->CallLogPop(1336);
2847  return(false);
2848  }
2849  Next = *NextTrackElementPtr;
2851  Utilities->CallLogPop(1337);
2852  return(true);
2853 }
2854 
2855 // ---------------------------------------------------------------------------
2856 
2858 {
2859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2861  {
2862  Utilities->CallLogPop(1338);
2863  return(false);
2864  }
2865  Next = *NextTrackElementPtr;
2867  Utilities->CallLogPop(1339);
2868  return(true);
2869 }
2870 
2871 // ---------------------------------------------------------------------------
2872 
2873 int TTrack::NumberOfGaps(int Caller)
2874 
2875 {
2876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2877  int Count = 0;
2878 
2879  if(TrackVector.size() == 0)
2880  {
2881  Utilities->CallLogPop(1340);
2882  return(0);
2883  }
2884  for(unsigned int x = 0; x < TrackVector.size(); x++)
2885  {
2886  if(TrackElementAt(1077, x).TrackType == GapJump)
2887  {
2888  Count++;
2889  }
2890  }
2891  Utilities->CallLogPop(1341);
2892  return(Count);
2893 }
2894 
2895 // ---------------------------------------------------------------------------
2897 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2898 // returns true for any unset gaps
2899 {
2900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2901  bool UnsetGaps = false;
2902 
2903  if(TrackVector.size() == 0)
2904  {
2905  Utilities->CallLogPop(445);
2906  return(false);
2907  }
2908  for(unsigned int x = 0; x < TrackVector.size(); x++)
2909  {
2910  if(TrackElementAt(1078, x).TrackType != GapJump)
2911  {
2912  for(unsigned int y = 0; y < 4; y++)
2913  {
2914  TrackElementAt(1079, x).Conn[y] = -1;
2915  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2916  }
2917  }
2918  else // GapJump
2919  {
2920 // int tempint = TrackElementAt(, x).Conn[0);
2921 
2922  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2923  {
2924  for(unsigned int y = 0; y < 4; y++)
2925  {
2926  TrackElementAt(1082, x).Conn[y] = -1;
2927  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2928  }
2929  UnsetGaps = true;
2930  continue; // to next 'x'
2931  }
2932  else // set, but may not have matching element, or that element may not be set
2933  {
2934  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2935  {
2936  TrackElementAt(1084, x).Conn[y] = -1;
2937  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2938  }
2939 
2940  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2941  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2942  {
2943  for(unsigned int y = 0; y < 4; y++)
2944  {
2945  TrackElementAt(1087, x).Conn[y] = -1;
2946  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2947  }
2948  UnsetGaps = true;
2949  continue; // to next 'x'
2950  }
2951 // here if gap connection is itself a GapJump
2952  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2953  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2954  // if not clear Conns & CLks & reset Lk[0]
2955  {
2956  for(unsigned int y = 0; y < 4; y++)
2957  {
2958  TrackElementAt(1090, x).Conn[y] = -1;
2959  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2960  }
2961  UnsetGaps = true;
2962  continue; // to next 'x'
2963  }
2964 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2965 // hence no more action needed on these Conns & CLks
2966  }
2967  } // else //gap jump
2968 
2969  } // for x...
2970  Utilities->CallLogPop(446);
2971  return(UnsetGaps);
2972 }
2973 
2974 // ---------------------------------------------------------------------------
2975 
2976 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2977 {
2978 // VecFile already open and its pointer at right place on calling
2979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2980  int TempInt;
2981 
2982  TrackClear(1);
2983 // load track elements
2984  int NumberOfActiveElements = 0;
2985 
2986  GraphicsFollow = false;
2987  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2988  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2989 
2990  if(MarkerString[MarkerString.Length()] == '1')
2991  {
2992  GraphicsFollow = true;
2993  }
2994  for(int x = 0; x < NumberOfActiveElements; x++)
2995  {
2996  VecFile >> TempInt; // TrackVectorNumber, not used
2997  VecFile >> TempInt; // SpeedTag
2998  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2999  VecFile >> TempInt;
3000  TrackElement.HLoc = TempInt;
3001  VecFile >> TempInt;
3002  TrackElement.VLoc = TempInt;
3003  if(TrackElement.TrackType == GapJump)
3004  {
3005  VecFile >> TempInt;
3006  TrackElement.ConnLinkPos[0] = TempInt;
3007  VecFile >> TempInt;
3008  TrackElement.Conn[0] = TempInt;
3009  }
3010  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3011  {
3012  VecFile >> TempInt;
3013  TrackElement.Attribute = TempInt;
3014  }
3015  if(TrackElement.TrackType == SignalPost)
3016  {
3017  VecFile >> TempInt;
3018  if(TempInt == 0)
3019  {
3020  TrackElement.CallingOnSet = false;
3021  }
3022  else
3023  {
3024  TrackElement.CallingOnSet = true;
3025  }
3026  }
3027  VecFile >> TempInt;
3028  TrackElement.Length01 = TempInt;
3029  VecFile >> TempInt;
3030  TrackElement.Length23 = TempInt;
3031  VecFile >> TempInt;
3032  if((TempInt != -1) && (TempInt < 10))
3033  {
3034  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3035  }
3036  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3037  {
3038  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3039  }
3040  TrackElement.SpeedLimit01 = TempInt;
3041  VecFile >> TempInt;
3042  if((TempInt != -1) && (TempInt < 10))
3043  {
3044  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3045  }
3046  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3047  {
3048  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3049  }
3050  TrackElement.SpeedLimit23 = TempInt;
3051 
3052  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3053  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3054  SetElementID(0, TrackElement);
3055  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3056 // new for v0.6
3057  if(TrackElement.TrackType == SignalPost)
3058  {
3059  if(Marker[1] == '3')
3060  {
3061  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3062  }
3063  else if(Marker[1] == '2')
3064  {
3065  TrackElement.SigAspect = TTrackElement::TwoAspect;
3066  }
3067  else if(Marker[1] == 'G')
3068  {
3069  TrackElement.SigAspect = TTrackElement::GroundSignal;
3070  }
3071  else
3072  {
3073  TrackElement.SigAspect = TTrackElement::FourAspect;
3074  }
3075  }
3076  if(TrackElement.SpeedTag != 0)
3077  {
3078  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3079  }
3080  }
3081  int NumberOfInactiveElements = 0;
3082 
3083  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3084  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3085  for(int x = 0; x < NumberOfInactiveElements; x++)
3086  {
3087  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3088  VecFile >> TempInt; // SpeedTag
3089  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3090  VecFile >> TempInt;
3091  TrackElement.HLoc = TempInt;
3092  VecFile >> TempInt;
3093  TrackElement.VLoc = TempInt;
3094  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3095  SetElementID(3, TrackElement);
3096  TrackPush(9, TrackElement);
3097  Utilities->LoadFileString(VecFile); // marker
3098  }
3099  bool LocError = false; // needed for TryToConnectTrack but not used
3100  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3101 
3102  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3103  {
3104  SetTrackFinished(true);
3105  }
3106  else
3107  {
3108  SetTrackFinished(false);
3109  }
3110 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3111 // CheckMapAndInactiveTrack(8);
3112 // CheckLocationNameMultiMap(10);
3113  Utilities->CallLogPop(448);
3114 }
3115 
3116 // ---------------------------------------------------------------------------
3117 
3118 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3119 {
3120 // VecFile already open and its pointer at right place on calling
3121  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3122 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3123 // & load into UserGraphicItem then store in UserGraphicVector
3124  UserGraphicVector.clear();
3125  TUserGraphicItem UGI;
3126  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3127 
3128  for(int x = 0; x < NumberOfGraphics; x++)
3129  {
3130  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3131  UGI.HPos = Utilities->LoadFileInt(VecFile);
3132  UGI.VPos = Utilities->LoadFileInt(VecFile);
3133  UGI.Width = 0; // provisional value
3134  UGI.Height = 0; // provisional value
3135  UGI.UserGraphic = NULL; // provisional value
3136  UserGraphicVector.push_back(UGI);
3137  }
3138 // now load the map & set Width, Height & TPicture*
3139  bool FileError = false;
3140 
3141  for(int x = 0; x < NumberOfGraphics; x++)
3142  {
3143  if(FileError)
3144  {
3145  break; // otherwise keeps going round the loop
3146  }
3147  UGI = UserGraphicVectorAt(0, x);
3148  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3149  {
3150  try
3151  {
3152 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3153  UGME.first = UGI.FileName;
3154  UGME.second = new TPicture;
3155  UGME.second->LoadFromFile(UGME.first); // errors caught below
3156  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3157  {
3158  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3159  }
3160  UGI.UserGraphic = UGME.second;
3161  UGI.Width = UGI.UserGraphic->Width;
3162  UGI.Height = UGI.UserGraphic->Height;
3163  UserGraphicVectorAt(1, x) = UGI;
3164  }
3165  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3166  {
3167  //message already sent in CheckUserGraphics
3168  FileError = true;
3169  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3170  if(!UserGraphicMap.empty())
3171  {
3172  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3173  {
3174  delete UGMIt->second;
3175  }
3176  UserGraphicMap.clear();
3177  }
3178  }
3179  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3180  {
3181  //message already sent in CheckUserGraphics
3182  FileError = true;
3183  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3184  if(!UserGraphicMap.empty())
3185  {
3186  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3187  {
3188  delete UGMIt->second;
3189  }
3190  UserGraphicMap.clear();
3191  }
3192  }
3193  }
3194  else
3195  {
3196  bool FoundInMap = false;
3197  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3198  {
3199  if(UGI.FileName == UGMIt->first) // already exists in map
3200  {
3201  UGI.UserGraphic = UGMIt->second;
3202  UGI.Width = UGI.UserGraphic->Width;
3203  UGI.Height = UGI.UserGraphic->Height;
3204  UserGraphicVectorAt(2, x) = UGI;
3205  FoundInMap = true;
3206  break;
3207  }
3208  }
3209  if(!FoundInMap)
3210  {
3211  try
3212  {
3214  UGME.first = UGI.FileName;
3215  UGME.second = new TPicture;
3216  UGME.second->LoadFromFile(UGME.first); // errors caught below
3217  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3218  {
3219  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3220  }
3221  UGI.UserGraphic = UGME.second;
3222  UGI.Width = UGI.UserGraphic->Width;
3223  UGI.Height = UGI.UserGraphic->Height;
3224  UserGraphicVectorAt(3, x) = UGI;
3225  }
3226  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3241  {
3242  //message already sent in CheckUserGraphics
3243  FileError = true;
3244  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3245  if(!UserGraphicMap.empty())
3246  {
3247  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3248  {
3249  delete UGMIt->second;
3250  }
3251  UserGraphicMap.clear();
3252  }
3253  }
3254  }
3255  }
3256  }
3257  Utilities->CallLogPop(2167);
3258 }
3259 
3260 // ---------------------------------------------------------------------------
3261 
3262 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3263 {
3264 // VecFile already open and its pointer at right place on calling
3265 // if GraphicsFollow true, then save Marker as **Active elements**1
3266 // save trackfinished flag
3267  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3268  TTrackElement TrackElement, InactiveTrackElement;
3269 
3270 // save track elements
3271  Utilities->SaveFileInt(VecFile, TrackVector.size());
3272  if(GraphicsFollow)
3273  {
3274  VecFile << "**Active elements**1" << '\0' << '\n';
3275  }
3276  else
3277  {
3278  VecFile << "**Active elements**" << '\0' << '\n';
3279  }
3280  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3281  {
3282  TrackElement = TrackElementAt(1092, x);
3283  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3284  VecFile << TrackElement.SpeedTag << '\n';
3285  VecFile << TrackElement.HLoc << '\n';
3286  VecFile << TrackElement.VLoc << '\n';
3287  if(TrackElement.TrackType == GapJump)
3288  {
3289  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3290  VecFile << TrackElement.Conn[0] << '\n';
3291  }
3292  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3293  {
3294  VecFile << TrackElement.Attribute << '\n';
3295  }
3296  if(TrackElement.TrackType == SignalPost)
3297  {
3298  if(TrackElement.CallingOnSet)
3299  {
3300  VecFile << int(1) << '\n';
3301  }
3302  else
3303  {
3304  VecFile << int(0) << '\n';
3305  }
3306  }
3307  VecFile << TrackElement.Length01 << '\n';
3308  VecFile << TrackElement.Length23 << '\n';
3309  VecFile << TrackElement.SpeedLimit01 << '\n';
3310  VecFile << TrackElement.SpeedLimit23 << '\n';
3311  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3312  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3313 // new for v0.6
3314  if(TrackElement.TrackType == SignalPost)
3315  {
3316  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3317  {
3318  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3319  }
3320  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3321  {
3322  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3323  }
3324  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3325  {
3326  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3327  }
3328  else // 4 aspect
3329  {
3330  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3331  }
3332  }
3333  else
3334  {
3335  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3336  }
3337  }
3338 
3339  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3340  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3341  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3342  {
3343  InactiveTrackElement = InactiveTrackElementAt(136, x);
3344  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3345  VecFile << InactiveTrackElement.SpeedTag << '\n';
3346  VecFile << InactiveTrackElement.HLoc << '\n';
3347  VecFile << InactiveTrackElement.VLoc << '\n';
3348  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3349  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3350  }
3351  Utilities->CallLogPop(449);
3352 }
3353 
3354 // ---------------------------------------------------------------------------
3355 
3356 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3357 {
3358 // VecFile already open and its pointer at right place on calling
3359 // check trackfinished flag
3360 // inactive elements follow immediately after active elements, no need to check for a marker between them
3361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3362  int TempInt;
3363 
3364  GraphicsFollow = false;
3365  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3366  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3367  {
3368  Utilities->CallLogPop(1513);
3369  return(false);
3370  }
3371 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3372  AnsiString MarkerString;
3373 
3374  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3375  {
3376  Utilities->CallLogPop(1758);
3377  return(false);
3378  }
3379  if(MarkerString[MarkerString.Length()] == '1')
3380  {
3381  GraphicsFollow = true;
3382  }
3383  for(int x = 0; x < NumberOfActiveElements; x++)
3384  {
3385  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3386  {
3387  Utilities->CallLogPop(1759);
3388  return(false);
3389  }
3390  VecFile >> TempInt;
3391  int SpeedTag = TempInt;
3392  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3393  {
3394  Utilities->CallLogPop(1514);
3395  return(false);
3396  }
3397  VecFile >> TempInt;
3398  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3399  {
3400  Utilities->CallLogPop(1495);
3401  return(false);
3402  }
3403  VecFile >> TempInt;
3404  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3405  {
3406  Utilities->CallLogPop(1497);
3407  return(false);
3408  }
3409  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3410  {
3411  VecFile >> TempInt;
3412  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3413  {
3414  Utilities->CallLogPop(1499);
3415  return(false);
3416  }
3417  VecFile >> TempInt;
3418  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3419  {
3420  Utilities->CallLogPop(1500);
3421  return(false);
3422  }
3423  }
3424  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3425  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3426  {
3427  VecFile >> TempInt;
3428  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3429  {
3430  Utilities->CallLogPop(1502);
3431  return(false);
3432  }
3433  }
3434  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3435  {
3436  VecFile >> TempInt;
3437  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3438  {
3439  Utilities->CallLogPop(1155);
3440  return(false);
3441  }
3442  }
3443  VecFile >> TempInt;
3444  if((TempInt < -1) || (TempInt > 999999)) // Length01
3445  {
3446  Utilities->CallLogPop(1503);
3447  return(false);
3448  }
3449  VecFile >> TempInt;
3450  if((TempInt < -1) || (TempInt > 999999)) // Length23
3451  {
3452  Utilities->CallLogPop(1504);
3453  return(false);
3454  }
3455  VecFile >> TempInt;
3456  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3457  {
3458  Utilities->CallLogPop(1505);
3459  return(false);
3460  }
3461  VecFile >> TempInt;
3462  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3463  {
3464  Utilities->CallLogPop(1506);
3465  return(false);
3466  }
3467  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3468  {
3469  Utilities->CallLogPop(1142);
3470  return(false); // LocationName
3471  }
3472  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3473  {
3474  Utilities->CallLogPop(1143);
3475  return(false); // ActiveTrackElementName
3476  }
3477  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3478  {
3479  Utilities->CallLogPop(1787);
3480  return(false); // marker
3481  }
3482  }
3483  int NumberOfInactiveElements = 0;
3484 
3485  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3486  if(NumberOfInactiveElements < 0) // No of active elements
3487  {
3488  Utilities->CallLogPop(1493);
3489  return(false);
3490  }
3491  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3492  {
3493  Utilities->CallLogPop(1764);
3494  return(false); // **Inactive elements** marker
3495  }
3496  for(int x = 0; x < NumberOfInactiveElements; x++)
3497  {
3498  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3499  {
3500  Utilities->CallLogPop(1765);
3501  return(false);
3502  }
3503  VecFile >> TempInt;
3504  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3505  {
3506  Utilities->CallLogPop(1494);
3507  return(false);
3508  }
3509  VecFile >> TempInt;
3510  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3511  {
3512  Utilities->CallLogPop(1496);
3513  return(false);
3514  }
3515  VecFile >> TempInt;
3516  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3517  {
3518  Utilities->CallLogPop(1498);
3519  return(false);
3520  }
3521  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3522  {
3523  Utilities->CallLogPop(1144);
3524  return(false); // LocationName
3525  }
3526  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3527  {
3528  Utilities->CallLogPop(1788);
3529  return(false); // marker
3530  }
3531  }
3532  Utilities->CallLogPop(1507);
3533  return(true);
3534 }
3535 
3536 // ---------------------------------------------------------------------------
3537 
3538 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3539 {
3540  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3541  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3542 
3543  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3544  {
3545  Utilities->CallLogPop(2168);
3546  return(false);
3547  }
3548  // filename in Graphics folder, then HPos, then VPos
3549  AnsiString FileName = "", TempStr = "";
3550 
3551  for(int x = 0; x < NumberOfGraphics; x++)
3552  {
3553  TPicture *TempPicture = new TPicture;
3554  try
3555  {
3556  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3557  {
3558  Utilities->CallLogPop(2169);
3559  delete TempPicture;
3560  return(false);
3561  }
3562  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3563  delete TempPicture;
3564  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3565  {
3566  Utilities->CallLogPop(2170);
3567  return(false);
3568  }
3569  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3570  {
3571  Utilities->CallLogPop(2171);
3572  return(false);
3573  }
3574  }
3575  catch(const EInvalidGraphic &e) //non error catch
3576  {
3577  //move file pointer to end of graphic section for later checks in session files
3578  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3579  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3580  for(int y = x + 1; y < NumberOfGraphics; y++)
3581  {
3582  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3583  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3584  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3585  }
3586  ShowMessage(FileName +
3587  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3588  Utilities->CallLogPop(2172);
3589  delete TempPicture;
3590  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3591  }
3592  catch(const Exception &e) //non error catch
3593  {
3594  //move file pointer to end of graphic section for later checks in session files
3595  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3596  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3597  for(int y = x + 1; y < NumberOfGraphics; y++)
3598  {
3599  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3600  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3601  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3602  }
3603  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3604  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3605  Utilities->CallLogPop(2173);
3606  delete TempPicture;
3607  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3608  }
3609  }
3610  Utilities->CallLogPop(2174);
3611  return(true);
3612 }
3613 
3614 // ---------------------------------------------------------------------------
3615 
3616 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3617 {
3618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3619  int VecSize = Track->BarriersDownVector.size();
3620 
3621  Utilities->SaveFileInt(OutFile, VecSize);
3622  for(int x = 0; x < VecSize; x++)
3623  {
3625  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3626  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3627  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3628  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3629  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3630  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3631  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3632  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3633  }
3634  Utilities->CallLogPop(1963);
3635 }
3636 
3637 // ---------------------------------------------------------------------------
3638 
3639 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3640 {
3641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3642  int VecSize = Track->ChangingLCVector.size();
3643 
3644  Utilities->SaveFileInt(OutFile, VecSize);
3645  for(int x = 0; x < VecSize; x++)
3646  {
3648  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3649  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3650  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3651  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3652  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3653  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3654  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3655  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3656  }
3657  Utilities->CallLogPop(1980);
3658 }
3659 
3660 // ---------------------------------------------------------------------------
3661 
3662 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3663 {
3664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3665  int VecSize = Utilities->LoadFileInt(VecFile);
3666 
3667  for(int x = 0; x < VecSize; x++)
3668  {
3669  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3670  {
3671  Utilities->CallLogPop(1970);
3672  return(false);
3673  }
3674  if(!Utilities->CheckFileBool(VecFile))
3675  {
3676  Utilities->CallLogPop(1971);
3677  return(false);
3678  }
3679  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3680  {
3681  Utilities->CallLogPop(1972);
3682  return(false);
3683  }
3684  if(!Utilities->CheckFileDouble(VecFile))
3685  {
3686  Utilities->CallLogPop(1973);
3687  return(false);
3688  }
3689  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3690  {
3691  Utilities->CallLogPop(1974);
3692  return(false);
3693  }
3694  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3695  {
3696  Utilities->CallLogPop(1975);
3697  return(false);
3698  }
3699  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3700  {
3701  Utilities->CallLogPop(1976);
3702  return(false);
3703  }
3704  if(!Utilities->CheckFileDouble(VecFile))
3705  {
3706  Utilities->CallLogPop(1977);
3707  return(false);
3708  }
3709  }
3710  Utilities->CallLogPop(1978);
3711  return(true);
3712 }
3713 
3714 // ---------------------------------------------------------------------------
3715 
3716 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3717 {
3718  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3719  int VecSize = Utilities->LoadFileInt(VecFile);
3720 
3721  for(int x = 0; x < VecSize; x++)
3722  {
3723  TActiveLevelCrossing TALC;
3724  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3725  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3726  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3727  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3728  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3729  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3730  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3731  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3732  BarriersDownVector.push_back(TALC);
3733  }
3734  Utilities->CallLogPop(1979);
3735 }
3736 
3737 // ---------------------------------------------------------------------------
3738 
3739 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3740 /*
3741  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3742  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3743  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3744 */
3745 {
3746  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3747  TTrackElement Next;
3748 
3749 // Disp->ClearDisplay();
3751  while(ReturnNextInactiveTrackElement(0, Next))
3752  {
3753  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3754  {
3755  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3756  {
3757  // only plot if on screen, to save time
3758  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3760  {
3761  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3762  }
3763  }
3764  }
3765  }
3766 
3767  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3768 
3769  NextTrackElementPtr = TrackVector.begin();
3770  while(ReturnNextTrackElement(0, Next))
3771  {
3772  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3773  {
3774  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3776  {
3777  if(Next.TrackType == Points)
3778  {
3779  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3780  }
3781  else if(Next.TrackType == SignalPost)
3782  {
3783  PlotSignal(9, Next, Disp);
3784  }
3785  else if(Next.TrackType == GapJump)
3786  {
3787  PlotGap(0, Next, Disp);
3788  }
3789  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3790  {
3791  PlotContinuation(0, Next, Disp);
3792  }
3793  else
3794  {
3795  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3796  }
3797  }
3798  }
3799  }
3800 
3801  if(BothPointFilletsAndBasicLCs)
3802  {
3804  while(ReturnNextInactiveTrackElement(4, Next))
3805  {
3806  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3807  {
3808  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3809  {
3810  // only plot if on screen, to save time, & OK as plotting one by one here
3811  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3813  {
3814  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3815  {
3816  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3817  }
3818  else
3819  {
3820  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3821  }
3822  }
3823  }
3824  }
3825  }
3826  }
3827  Disp->Update();
3828  Utilities->CallLogPop(468);
3829 }
3830 
3831 // ---------------------------------------------------------------------------
3832 
3833 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3834 {
3835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3836  if(UserGraphicVector.empty())
3837  {
3838  Utilities->CallLogPop(2175);
3839  return;
3840  }
3841  TUserGraphicItem UGI;
3842 
3843  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3844  {
3845  UGI = UserGraphicVectorAt(4, x);
3846  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3847  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3848  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3849  {
3850  Disp->PlotAndAddUserGraphic(0, UGI);
3851  }
3852  }
3853  Disp->Update();
3854  Utilities->CallLogPop(2176);
3855 }
3856 
3857 // ---------------------------------------------------------------------------
3858 
3859 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3860 /*
3861  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3862 */
3863 {
3864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3865 // need to change graphics back to black on white if have a dark background
3866  TColor OldTransparentColour = Utilities->clTransparent;
3867 
3869  {
3870  Utilities->clTransparent = TColor(0xFFFFFF); // white
3873  }
3874  TTrackElement Next;
3875 
3876  Bitmap->Canvas->CopyMode = cmSrcCopy;
3878  Graphics::TBitmap *GraphicOutput;
3879 
3880  while(ReturnNextInactiveTrackElement(2, Next))
3881  {
3882  GraphicOutput = Next.GraphicPtr;
3883  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3884  {
3885  if(Next.LocationName == "") // plot as named or unnamed (striped)
3886  {
3887  // default is not striped
3888  switch(Next.SpeedTag)
3889  {
3890  case 76: // t platform
3891  GraphicOutput = RailGraphics->gl76Striped;
3892  break;
3893 
3894  case 77: // h platform
3895  GraphicOutput = RailGraphics->bm77Striped;
3896  break;
3897 
3898  case 78: // v platform
3899  GraphicOutput = RailGraphics->bm78Striped;
3900  break;
3901 
3902  case 79: // r platform
3903  GraphicOutput = RailGraphics->gl79Striped;
3904  break;
3905 
3906  case 96: // concourse
3907  GraphicOutput = RailGraphics->ConcourseStriped;
3908  break;
3909 
3910  case 129: // v footbridge
3911  GraphicOutput = RailGraphics->gl129Striped;
3912  break;
3913 
3914  case 130: // h footbridge
3915  GraphicOutput = RailGraphics->gl130Striped;
3916  break;
3917 
3918  case 131: // non-station named loc
3919  GraphicOutput = RailGraphics->bmNameStriped;
3920  break;
3921 
3922  case 145: // v underpass
3923  GraphicOutput = RailGraphics->gl145Striped;
3924  break;
3925 
3926  case 146: // h underpass
3927  GraphicOutput = RailGraphics->gl146Striped;
3928  break;
3929 
3930  default:
3931  GraphicOutput = Next.GraphicPtr;
3932  break;
3933  }
3934  }
3935  if(Next.SpeedTag == 144) // level crossing
3936  {
3937  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3938  {
3939  GraphicOutput = RailGraphics->LCBothVer;
3940  }
3941  else
3942  {
3943  GraphicOutput = RailGraphics->LCBothHor;
3944  }
3945  }
3946  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3947  }
3948  }
3949 
3950  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3951 
3952 
3953  NextTrackElementPtr = TrackVector.begin();
3954  while(ReturnNextTrackElement(2, Next))
3955  {
3956  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3957  {
3958  if(Next.TrackType == Points) // plot both fillets
3959  {
3960  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3961  if(Next.SpeedTag < 28)
3962  {
3963  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3965  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3967  }
3968  else if(Next.SpeedTag < 132)
3969  {
3970  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3971  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3972  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3973  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3974  }
3975  else
3976  {
3977  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3978  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3979  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3980  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3981  }
3982  }
3983  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3984  {
3985  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3986  {
3987  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3988  }
3989  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3990  {
3991  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3992  }
3993  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3994  {
3995  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3996  }
3997  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3998  {
3999  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4000  }
4001  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4002  {
4003  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4004  }
4005  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4006  {
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4008  }
4009  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4010  {
4011  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4012  }
4013  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4014  {
4015  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4016  }
4017  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4018  {
4019  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4020  }
4021  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4022  {
4023  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4024  }
4025  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4026  {
4027  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4028  }
4029  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4030  {
4031  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4032  }
4033  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4034  {
4035  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4036  }
4037  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4038  {
4039  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4040  }
4041  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4042  {
4043  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4044  }
4045  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4046  {
4047  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4048  }
4049  }
4050  // below added for version 0.6, only stop signals to be drawn
4051  else if(Next.TrackType == SignalPost)
4052  {
4053  for(int x = 0; x < 40; x++)
4054  {
4055  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4056  {
4057  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4058  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4059  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4060  int HOffset = 0;
4061  if(Next.SpeedTag > 73)
4062  {
4063  HOffset = 5;
4064  }
4065  else if(Next.SpeedTag == 71)
4066  {
4067  HOffset = 9;
4068  }
4069  int VOffset = 0;
4070  if(Next.SpeedTag == 69)
4071  {
4072  VOffset = 9;
4073  }
4074  else if(Next.SpeedTag == 72)
4075  {
4076  VOffset = 5;
4077  }
4078  else if(Next.SpeedTag == 74)
4079  {
4080  VOffset = 5;
4081  }
4082  Graphics::TBitmap *GraphicPtr;
4083  if(Next.SpeedTag > 71)
4084  {
4085  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4086  }
4087  else if(Next.SpeedTag < 70)
4088  {
4089  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4090  }
4091  else
4092  {
4093  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4094  }
4095  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4096  // plot special signal platform if present
4097  Graphics::TBitmap* SignalPlatformGraphic;
4098  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4099  {
4100  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4101  }
4102  // now plot signal (double yellow overwrites most of signal platform if present)
4103  // below amended for version 0.6
4105  {
4106  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4107  }
4108  else if(Next.SigAspect == TTrackElement::TwoAspect)
4109  {
4110  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4111  }
4112  else if(Next.SigAspect == TTrackElement::GroundSignal)
4113  {
4114  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4115  }
4116  else // 4 aspect
4117  {
4118  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4119  }
4120  break;
4121  }
4122  }
4123  }
4124  else
4125  {
4126  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4127  }
4128  }
4129  }
4130  if(OldTransparentColour != clB5G5R5)
4131  {
4132  Utilities->clTransparent = OldTransparentColour; // restore
4135  }
4136  Utilities->CallLogPop(1533);
4137 }
4138 
4139 // ---------------------------------------------------------------------------
4140 
4141 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4142 {
4143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4144  if(UserGraphicVector.empty())
4145  {
4146  Utilities->CallLogPop(2192);
4147  return;
4148  }
4149  else
4150  {
4151  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4152  {
4153  Bitmap->Canvas->CopyMode = cmSrcCopy;
4154  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4155  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4156  }
4157  }
4158  Utilities->CallLogPop(2193);
4159 }
4160 
4161 // ---------------------------------------------------------------------------
4162 
4163 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4164 /*
4165  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4166  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4167 */
4168 {
4169  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4170 // need to change graphics back to black on white if have a dark background
4171  TColor OldTransparentColour = Utilities->clTransparent;
4172 
4174  {
4175  Utilities->clTransparent = TColor(0xFFFFFF); // white
4178  }
4179  TTrackElement Next;
4180 
4181  Bitmap->Canvas->CopyMode = cmSrcCopy;
4183  Graphics::TBitmap *GraphicOutput;
4184 
4185  while(ReturnNextInactiveTrackElement(3, Next))
4186  {
4187  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4188  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4189  {
4190  if(Next.SpeedTag == 144) // level crossing
4191  {
4192  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4193  if(BaseElement == 1) // hor element
4194  {
4195  if(Next.Attribute == 1) // open to trains
4196  {
4197  GraphicOutput = RailGraphics->LCBothHor;
4198  }
4199  else // plot as closed to trains if in any other state
4200  {
4201  GraphicOutput = RailGraphics->LCBothVer;
4202  }
4203  }
4204  else // vert element
4205  {
4206  if(Next.Attribute == 1) // open to trains
4207  {
4208  GraphicOutput = RailGraphics->LCBothVer;
4209  }
4210  else // plot as closed to trains if in any other state
4211  {
4212  GraphicOutput = RailGraphics->LCBothHor;
4213  }
4214  }
4215  }
4216  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4217  }
4218  }
4219 
4220  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4221 
4222  NextTrackElementPtr = TrackVector.begin();
4223  while(ReturnNextTrackElement(3, Next))
4224  {
4225  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4226  {
4227  if(Next.TrackType == Points) // plot active fillet
4228  {
4229  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4230  if(Next.SpeedTag < 28)
4231  {
4232  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4234  }
4235  else if(Next.SpeedTag < 132)
4236  {
4237  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4239  }
4240  else
4241  {
4242  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4244  }
4245  }
4246  else if(Next.TrackType == GapJump) // plot as connected
4247  {
4248  if(Next.SpeedTag == 88)
4249  {
4250  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4251  }
4252  else if(Next.SpeedTag == 89)
4253  {
4254  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4255  }
4256  else if(Next.SpeedTag == 90)
4257  {
4258  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4259  }
4260  else if(Next.SpeedTag == 91)
4261  {
4262  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4263  }
4264  else if(Next.SpeedTag == 92)
4265  {
4266  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4267  }
4268  else if(Next.SpeedTag == 93)
4269  {
4270  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4271  }
4272  else if(Next.SpeedTag == 94)
4273  {
4274  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4275  }
4276  else if(Next.SpeedTag == 95)
4277  {
4278  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4279  }
4280  }
4281  else if(Next.TrackType == SignalPost) // plot in correct colour
4282  {
4283  for(int x = 0; x < 40; x++)
4284  {
4285  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4286  {
4287  // plot blank first, then plot platform if present - (always not striped for operating railway)
4288  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4289  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4290  int HOffset = 0;
4291  if(Next.SpeedTag > 73)
4292  {
4293  HOffset = 5;
4294  }
4295  else if(Next.SpeedTag == 71)
4296  {
4297  HOffset = 9;
4298  }
4299  int VOffset = 0;
4300  if(Next.SpeedTag == 69)
4301  {
4302  VOffset = 9;
4303  }
4304  else if(Next.SpeedTag == 72)
4305  {
4306  VOffset = 5;
4307  }
4308  else if(Next.SpeedTag == 74)
4309  {
4310  VOffset = 5;
4311  }
4312  Graphics::TBitmap *GraphicPtr;
4313  if(Next.SpeedTag > 71)
4314  {
4315  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4316  }
4317  else if(Next.SpeedTag < 70)
4318  {
4319  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4320  }
4321  else
4322  {
4323  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4324  }
4325  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4326  // plot special signal platform if present
4327  Graphics::TBitmap* SignalPlatformGraphic;
4328  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4329  {
4330  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4331  }
4332  // now plot signal (double yellow overwrites most of signal platform if present)
4333  // below amended for version 0.6
4335  {
4336  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4337  }
4338  else if(Next.SigAspect == TTrackElement::TwoAspect)
4339  {
4340  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4341  }
4342  else if(Next.SigAspect == TTrackElement::GroundSignal)
4343  {
4344  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4345  }
4346  else // 4 aspect
4347  {
4348  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4349  }
4350  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4351  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4352  {
4353  if(Next.SpeedTag == 68)
4354  {
4355  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4356  }
4357  if(Next.SpeedTag == 69)
4358  {
4359  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4360  }
4361  if(Next.SpeedTag == 70)
4362  {
4363  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4364  }
4365  if(Next.SpeedTag == 71)
4366  {
4367  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4368  }
4369  if(Next.SpeedTag == 72)
4370  {
4371  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4372  }
4373  if(Next.SpeedTag == 73)
4374  {
4375  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4376  }
4377  if(Next.SpeedTag == 74)
4378  {
4379  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4380  }
4381  if(Next.SpeedTag == 75)
4382  {
4383  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4384  }
4385  }
4386  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4387  {
4388  for(int x = 0; x < 40; x++)
4389  {
4390  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4391  {
4392  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4393  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4394  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4395  // plot special signal platform if present
4396  Graphics::TBitmap* SignalPlatformGraphic;
4397  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4398  {
4399  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4400  }
4401  // now plot signal
4402  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4403  break;
4404  }
4405  }
4406  }
4407  break;
4408  }
4409  }
4410  }
4411  else
4412  {
4413  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4414  }
4415  }
4416  }
4417  if(OldTransparentColour != clB5G5R5)
4418  {
4419  Utilities->clTransparent = OldTransparentColour; // restore
4422  }
4423  Utilities->CallLogPop(1701);
4424 }
4425 
4426 // ---------------------------------------------------------------------------
4427 
4428 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4429 {
4430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4431  for(unsigned int x = 0; x < TrackVector.size(); x++)
4432  {
4433  if(TrackElementAt(1093, x).TrackType == GapJump)
4434  {
4435  if(TrackElementAt(1094, x).Conn[0] > -1)
4436  {
4437  continue; // to next 'x' value as this element has already been set
4438  }
4439  // here if identify a GapJump element not yet set
4440  GapPos = x;
4441  GapHLoc = TrackElementAt(1095, x).HLoc;
4442  GapVLoc = TrackElementAt(1096, x).VLoc;
4443  // highlight it
4445  Utilities->CallLogPop(469);
4446  return(true);
4447  }
4448  }
4449  Utilities->CallLogPop(470);
4450  return(false);
4451 }
4452 
4453 // ---------------------------------------------------------------------------
4454 
4455 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4456 {
4457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4458  AnsiString(VLoc));
4459  int Position;
4460  TTrackElement TrackElement;
4461 
4462  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4463  {
4464  Utilities->CallLogPop(471);
4465  return(false); // not found
4466  }
4467  if(TrackElement.TrackType != GapJump)
4468  {
4469  Utilities->CallLogPop(472);
4470  return(false); // found something but not a gap
4471  }
4472  if(Position == GapPos)
4473  {
4474  Utilities->CallLogPop(473);
4475  return(false); // selected original gap
4476  }
4477  if(TrackElementAt(1097, Position).Conn[0] != -1)
4478  {
4479  Utilities->CallLogPop(474);
4480  return(false); // already selected
4481  }
4482  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4483  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4484  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4485  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4486 // now highlight the selected location
4487  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4488  Utilities->CallLogPop(475);
4489  return(true);
4490 }
4491 
4492 // ---------------------------------------------------------------------------
4493 
4494 bool TTrack::GapsUnset(int Caller)
4495 // returns true if there are gaps and any are unset
4496 {
4497  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4498  if(TrackVector.size() == 0)
4499  {
4500  Utilities->CallLogPop(476);
4501  return(false);
4502  }
4503  for(unsigned int x = 0; x < TrackVector.size(); x++)
4504  {
4505  if(TrackElementAt(1102, x).TrackType == GapJump)
4506  {
4507  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4508  {
4509  Utilities->CallLogPop(477);
4510  return(true);
4511  }
4512  else // set, but may not have matching element, or that element may not be set
4513  {
4514  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4515  // check that the element pointed to by the gap link is a GapJump
4516  {
4517  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4518  Utilities->CallLogPop(1137);
4519  return(false);
4520  }
4521 // here if gap connection is itself a GapJump
4522  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4523  // check that the element pointed to by the gap link is a GapJump & that its gap link
4524  // points back to 'x'
4525  {
4526  Utilities->CallLogPop(478);
4527  return(true);
4528  }
4529 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4530  }
4531  } // if(TrackElementAt(, x).TrackType == GapJump)
4532 
4533  } // for x...
4534  Utilities->CallLogPop(479);
4535  return(false);
4536 }
4537 
4538 // ---------------------------------------------------------------------------
4539 
4540 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4541 {
4542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4543  for(unsigned int x = 0; x < TrackVector.size(); x++)
4544  {
4545  if(TrackElementAt(1110, x).TrackType == GapJump)
4546  {
4547  Utilities->CallLogPop(1105);
4548  return(false);
4549  }
4550  }
4551  Utilities->CallLogPop(1106);
4552  return(true);
4553 }
4554 
4555 // ---------------------------------------------------------------------------
4556 
4557 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4558 {
4559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4560  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4561  {
4562  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4563  {
4564  Utilities->CallLogPop(1107);
4565  return(false);
4566  }
4567  }
4568  for(unsigned int x = 0; x < TrackVector.size(); x++)
4569  {
4570  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4571  {
4572  Utilities->CallLogPop(1108);
4573  return(false);
4574  }
4575  }
4576  Utilities->CallLogPop(1109);
4577  return(true);
4578 }
4579 
4580 // ---------------------------------------------------------------------------
4581 
4583 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4584 // returns false otherwise or if there are no NamedLocationElements
4585 {
4586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4587  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4588  {
4589  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4590  {
4591  if(InactiveTrackElementAt(139, x).LocationName == "")
4592  {
4593  Utilities->CallLogPop(1110);
4594  return(true);
4595  }
4596  }
4597  }
4598  for(unsigned int x = 0; x < TrackVector.size(); x++)
4599  {
4600  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4601  {
4602  if(TrackElementAt(1113, x).LocationName == "")
4603  {
4604  Utilities->CallLogPop(1111);
4605  return(true);
4606  }
4607  }
4608  }
4609  Utilities->CallLogPop(1112);
4610  return(false);
4611 }
4612 
4613 // ---------------------------------------------------------------------------
4614 
4615 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4616 {
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4618  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4619  Utilities->CallLogPop(480);
4620 }
4621 
4622 // ---------------------------------------------------------------------------
4623 
4625 {
4626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4627  if(TrackVector.size() == 0)
4628  {
4629  Utilities->CallLogPop(481);
4630  return;
4631  }
4632  for(unsigned int x = 0; x < TrackVector.size(); x++)
4633  {
4634  if(TrackElementAt(1114, x).TrackType == GapJump)
4635  {
4636  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4637  {
4638  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4639  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4640  {
4641  TrackElementAt(1118, x).Conn[0] = -1;
4642  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4643  continue; // to next 'x'
4644  }
4645 // here if gap connection is itself a GapJump
4646  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4647  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4648  // if not clear Conns & CLks
4649  {
4650  TrackElementAt(1121, x).Conn[0] = -1;
4651  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4652  continue; // to next 'x'
4653  }
4654 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4655 // hence no more action needed on these Conns & CLks
4656  }
4657  } // else //gap jump
4658 
4659  } // for x...
4660 // throw Exception("Test Exception");//test
4661  Utilities->CallLogPop(482);
4662 }
4663 
4664 // ---------------------------------------------------------------------------
4665 
4666 void TTrack::ResetSignals(int Caller)
4667 {
4668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4669  for(unsigned int x = 0; x < TrackVector.size(); x++)
4670  {
4671  if(TrackElementAt(1123, x).TrackType == SignalPost)
4672  {
4673  TrackElementAt(1124, x).Attribute = 0;
4674  }
4675  }
4676  Utilities->CallLogPop(483);
4677 }
4678 
4679 // ---------------------------------------------------------------------------
4680 
4681 void TTrack::ResetPoints(int Caller)
4682 {
4683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4684  for(unsigned int x = 0; x < TrackVector.size(); x++)
4685  {
4686  if(TrackElementAt(1125, x).TrackType == Points)
4687  {
4688  TrackElementAt(1126, x).Attribute = 0;
4689  }
4690  }
4691  Utilities->CallLogPop(484);
4692 }
4693 
4694 // ---------------------------------------------------------------------------
4695 
4696 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4697 {
4698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4699  if(TrackVector.empty())
4700  {
4701  TrackMap.clear();
4702  Utilities->CallLogPop(485);
4703  return(true);
4704  }
4705 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4706  THVPair TrackMapKeyPair;
4707 
4708  NewVector.clear();
4709  TTrackMapIterator TrackMapPtr;
4710 
4711  if(!TrackMap.empty())
4712  {
4713  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4714  {
4715  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4716  }
4717  }
4718  if(NewVector.size() != TrackMap.size())
4719  {
4720  throw Exception("Error - Map & Vector different sizes");
4721  }
4722  unsigned int NonZeroCount = 0;
4723 
4724  for(unsigned int x = 0; x < TrackVector.size(); x++)
4725  {
4726  if(TrackElementAt(1127, x).TrackType != Erase)
4727  {
4728  NonZeroCount++;
4729  }
4730  }
4731  if(NewVector.size() != NonZeroCount)
4732  {
4733  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4734  }
4736  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4737  TTrackMapEntry TrackMapEntry;
4738 
4739  for(unsigned int x = 0; x < TrackVector.size(); x++)
4740  {
4741  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4742  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4743  TrackMapEntry.first = TrackMapKeyPair;
4744  TrackMapEntry.second = x;
4745  if(!(TrackMap.insert(TrackMapEntry).second))
4746  {
4747  throw Exception("Error - map insertion failure, TrackVector in error");
4748  }
4749  }
4750 // All track now relocated in TrackVector, reset all Conns & CLks
4751  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4752  {
4753  for(unsigned int y = 0; y < 4; y++)
4754  {
4755  TrackElementAt(1130, x).Conn[y] = -1;
4756  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4757  }
4758  }
4759  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4760  CheckMapAndTrack(4); // test
4761  CheckMapAndInactiveTrack(4); // test
4762  CheckLocationNameMultiMap(8); // test
4763  if(!ResetGapsFromGapMap(1))
4764  {
4765  Utilities->CallLogPop(489);
4766  return(false);
4767  }
4768  Utilities->CallLogPop(490);
4769  return(true);
4770 }
4771 
4772 // ---------------------------------------------------------------------------
4773 
4774 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4775 {
4776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4777  GapMap.clear();
4778  THVPair GapMapKeyPair, GapMapValuePair;
4779  TGapMapEntry GapMapEntry;
4780 
4781  for(unsigned int x = 0; x < TrackVector.size(); x++)
4782  {
4783  if(TrackElementAt(1132, x).TrackType == GapJump)
4784  {
4785  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4786  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4787  GapMapEntry.first = GapMapKeyPair;
4788  if(TrackElementAt(1135, x).Conn[0] == -1)
4789  {
4790  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4791  }
4792  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4793  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4794  GapMapEntry.second = GapMapValuePair;
4795  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4796  {
4797  GapMap.insert(GapMapEntry);
4798  }
4799  }
4800  }
4801  Utilities->CallLogPop(492);
4802 }
4803 
4804 // ---------------------------------------------------------------------------
4805 
4806 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4807 {
4808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4809  LocError = false;
4810  bool CheckForLinks = false;
4811 
4812  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4813  {
4814  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4815  {
4816  continue; // skip blank elements
4817  }
4818 // check footcrossing linkages
4819  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4820  {
4821  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4822  {
4823  ShowMessage(
4824  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4825  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4826  "can't connect to an underpass or vice versa)");
4827  HLoc = TrackElementAt(1141, x).HLoc;
4828  VLoc = TrackElementAt(1142, x).VLoc;
4829  LocError = true;
4830  Utilities->CallLogPop(493);
4831  return(false);
4832  }
4833  }
4834  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4835  {
4836  CheckForLinks = false;
4837  if(TrackElementAt(1143, x).Link[y] <= 0)
4838  {
4839  continue; // no link
4840  }
4841  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4842  {
4843  continue; // buffer
4844  }
4845  if(TrackElementAt(1146, x).Config[y] == Gap)
4846  {
4847  continue; // gaps set later from GapMap
4848 
4849  }
4850  // get required H & V for track element joining link 'y'
4851  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4852  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4853  // find track element if present
4854  bool ConnectionFoundFlag;
4855  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4856  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4857  {
4858  ShowMessage("Can't have a track element adjacent to a continuation exit");
4859  HLoc = TrackElementAt(1152, x).HLoc;
4860  VLoc = TrackElementAt(1153, x).VLoc;
4861  LocError = true;
4862  if(FinalCall)
4863  {
4864  throw Exception("Error in final track linkage - continuation adjacent to another element");
4865  }
4866  Utilities->CallLogPop(1539);
4867  return(false);
4868  }
4869  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4870  {
4871  continue;
4872  }
4873  if(ConnectionFoundFlag)
4874  {
4875  TrackElementAt(1156, x).Conn[y] = VecPos;
4876  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4877  bool LinkFoundFlag = false;
4878  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4879  {
4880  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4881  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4882  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4883  }
4884  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4885  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4886  {
4887  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4888  // need room for a train (2 elements) without fouling points or signals
4889  }
4890  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4891  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4892  {
4893  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4894  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4895  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4896  // be named but needs the adjacent element named too
4897  }
4898  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4899  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4900  {
4901  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4902  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4903  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4904  }
4905  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4906  {
4907  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4908  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4909  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4910  }
4911  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4912  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4913  {
4914  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4915  }
4916  else
4917  {
4918  CheckForLinks = true;
4919  }
4920  if(CheckForLinks)
4921  {
4922  for(unsigned int a = 0; a < 4; a++)
4923  {
4924  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
4925  (TrackElementAt(1181, VecPos).Config[a] != Gap))
4926  {
4927  TrackElementAt(1182, x).ConnLinkPos[y] = a;
4928  // note - this ensures that if the connecting element is a leading point
4929  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4930  // (Points have the same link value for both [0] and [2])
4931  LinkFoundFlag = true;
4932  break; // stop after first find or will find later link for leading point
4933  }
4934  }
4935  }
4936  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4937  if(!LinkFoundFlag)
4938  {
4939  HLoc = TrackElementAt(1183, x).HLoc;
4940  VLoc = TrackElementAt(1184, x).VLoc;
4941  LocError = true;
4942  if(FinalCall)
4943  {
4944  throw Exception("Error in final track linkage - invalid link");
4945  }
4946  Utilities->CallLogPop(494);
4947  return(false);
4948  }
4949  }
4950  // if there isn't a connection set the invert values for the offending element
4951  else // if(ConnectionFoundFlag)
4952  {
4953  HLoc = TrackElementAt(1185, x).HLoc;
4954  VLoc = TrackElementAt(1186, x).VLoc;
4955  LocError = true;
4956  if(FinalCall)
4957  {
4958  throw Exception("Error in final track linkage - connection not found");
4959  }
4960  Utilities->CallLogPop(495);
4961  return(false);
4962  }
4963  }
4964  } // for(unsigned int x=0;x<TrackVector.size();x++)
4965 
4966  if(FinalCall)
4967  {
4969  }
4970 // final check
4971  bool ConnErrorFlag = false;
4972 
4973  for(unsigned int x = 0; x < TrackVector.size(); x++)
4974  {
4975  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
4976  {
4977  ConnErrorFlag = true;
4978  }
4979  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
4980  {
4981  ConnErrorFlag = true;
4982  }
4983  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
4984  {
4985  ConnErrorFlag = true;
4986  }
4987  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
4988  {
4989  ConnErrorFlag = true;
4990  }
4991  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4992  {
4993  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
4994  {
4995  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
4996  {
4997  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4998  }
4999  }
5000  }
5001  }
5002  if(ConnErrorFlag)
5003  {
5004  if(FinalCall)
5005  {
5006  throw Exception("ConnError in LinkTrack - Final");
5007  }
5008  else
5009  {
5010  throw Exception("ConnError in LinkTrack - Precheck");
5011  }
5012  }
5013  bool CLkErrorFlag = false;
5014 
5015  for(unsigned int x = 0; x < TrackVector.size(); x++)
5016  {
5017  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5018  {
5019  CLkErrorFlag = true;
5020  }
5021  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5022  {
5023  CLkErrorFlag = true;
5024  }
5025  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5026  {
5027  CLkErrorFlag = true;
5028  }
5029  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5030  {
5031  CLkErrorFlag = true;
5032  }
5033  }
5034 
5035  if(CLkErrorFlag)
5036  {
5037  if(FinalCall)
5038  {
5039  throw Exception("CLkError in LinkTrack - Final");
5040  }
5041  else
5042  {
5043  throw Exception("CLkError in LinkTrack - Precheck");
5044  }
5045  }
5046 // set element lengths to min of 10m
5047  for(unsigned int x = 0; x < TrackVector.size(); x++)
5048  {
5049  if(TrackElementAt(1214, x).TrackType == Erase)
5050  {
5051  continue; // skip blank elements
5052  }
5053  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5054  {
5055  TrackElementAt(1216, x).Length01 = 10;
5056  }
5057  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5058  {
5059  TrackElementAt(1219, x).Length23 = 10;
5060  }
5061  }
5062 
5063  if(FinalCall) // ONLY at FinalCall, no point calling twice
5064  {
5065  CalcHLocMinEtc(3);
5066  }
5067 
5068  Utilities->CallLogPop(497);
5069  return(true);
5070 }
5071 
5072 // ---------------------------------------------------------------------------
5073 
5074 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5075 {
5076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5077  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5078  {
5079  if(TrackElementAt(1220, x).TrackType == Erase)
5080  {
5081  continue; // skip blank elements
5082 
5083  }
5084 // check footcrossing linkages
5085  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5086  {
5087  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5088  {
5089  Utilities->CallLogPop(1127);
5090  return(false);
5091  }
5092  }
5093  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5094  {
5095  if(TrackElementAt(1223, x).Link[y] <= 0)
5096  {
5097  continue; // no link
5098  }
5099  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5100  {
5101  continue; // buffer
5102  }
5103  if(TrackElementAt(1226, x).Config[y] == Gap)
5104  {
5105  continue; // gaps set later from GapMap
5106 
5107  }
5108  // get required H & V for track element joining link 'y'
5109  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5110  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5111  // find track element if present
5112  bool ConnectionFoundFlag;
5113  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5114  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5115  {
5116  if(FinalCall)
5117  {
5118  throw Exception("Error in final track linkage - continuation adjacent to another element");
5119  }
5120  Utilities->CallLogPop(1540);
5121  return(false);
5122  }
5123  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5124  {
5125  continue;
5126  }
5127  if(ConnectionFoundFlag)
5128  {
5129  TrackElementAt(1234, x).Conn[y] = VecPos;
5130  bool LinkFoundFlag = false;
5131  // find connecting link in the newly found track element if there is one & make checks
5132  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5133  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5134  {
5135  Utilities->CallLogPop(1541);
5136  return(false);
5137  }
5138  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5139  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5140  {
5141  Utilities->CallLogPop(1542);
5142  return(false);
5143  }
5144  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5145  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5146  {
5147  Utilities->CallLogPop(1543);
5148  return(false);
5149  }
5150  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5151  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5152  {
5153  Utilities->CallLogPop(1981);
5154  return(false);
5155  }
5156 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5157  else if(TrackElementAt(, x).TrackType == Continuation)
5158  {
5159  int H = TrackElementAt(, x).HLoc;
5160  int V = TrackElementAt(, x).VLoc;
5161  bool FoundFlag = false;
5162  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5163  if(FoundFlag)
5164  {
5165  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5166  {
5167  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5168  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5169  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5170  if(FoundFlag)
5171  {
5172  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5173  {
5174  Utilities->CallLogPop();
5175  return false;
5176  }
5177  }
5178  else
5179  {
5180  Utilities->CallLogPop();
5181  return false;
5182  }
5183  }
5184  }
5185  }
5186 */
5187  for(unsigned int a = 0; a < 4; a++)
5188  {
5189  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5190  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5191  {
5192  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5193  // note - this ensures that if the connecting element is a leading point
5194  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5195  // (Points have the same link value for both [0] and [2])
5196  LinkFoundFlag = true;
5197  break; // stop after first find or will find later link for leading point
5198  }
5199  }
5200  if(!LinkFoundFlag)
5201  {
5202  if(FinalCall)
5203  {
5204  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5205  }
5206  Utilities->CallLogPop(1128);
5207  return(false);
5208  }
5209  }
5210  else // if(ConnectionFoundFlag)
5211  {
5212  if(FinalCall)
5213  {
5214  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5215  }
5216  Utilities->CallLogPop(1129);
5217  return(false);
5218  }
5219  }
5220  } // for(unsigned int x=0;x<TrackVector.size();x++)
5221 
5222  if(FinalCall)
5223  {
5225  }
5226 // final check
5227  bool ConnErrorFlag = false;
5228 
5229  for(unsigned int x = 0; x < TrackVector.size(); x++)
5230  {
5231  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5232  {
5233  ConnErrorFlag = true;
5234  }
5235  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5236  {
5237  ConnErrorFlag = true;
5238  }
5239  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5240  {
5241  ConnErrorFlag = true;
5242  }
5243  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5244  {
5245  ConnErrorFlag = true;
5246  }
5247  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5248  {
5249  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5250  {
5251  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5252  {
5253  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5254  }
5255  }
5256  }
5257  }
5258  if(ConnErrorFlag)
5259  {
5260  if(FinalCall)
5261  {
5262  throw Exception("ConnError in LinkTrack - Final");
5263  }
5264  else
5265  {
5266  throw Exception("ConnError in LinkTrack - Precheck");
5267  }
5268  }
5269  bool CLkErrorFlag = false;
5270 
5271  for(unsigned int x = 0; x < TrackVector.size(); x++)
5272  {
5273  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5274  {
5275  CLkErrorFlag = true;
5276  }
5277  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5278  {
5279  CLkErrorFlag = true;
5280  }
5281  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5282  {
5283  CLkErrorFlag = true;
5284  }
5285  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5286  {
5287  CLkErrorFlag = true;
5288  }
5289  }
5290 
5291  if(CLkErrorFlag)
5292  {
5293  if(FinalCall)
5294  {
5295  throw Exception("CLkError in LinkTrack - Final");
5296  }
5297  else
5298  {
5299  throw Exception("CLkError in LinkTrack - Precheck");
5300  }
5301  }
5302 // set element lengths to min of 10m
5303  for(unsigned int x = 0; x < TrackVector.size(); x++)
5304  {
5305  if(TrackElementAt(1284, x).TrackType == Erase)
5306  {
5307  continue; // skip blank elements
5308  }
5309  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5310  {
5311  TrackElementAt(1286, x).Length01 = 10;
5312  }
5313  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5314  {
5315  TrackElementAt(1289, x).Length23 = 10;
5316  }
5317  }
5318 
5319  if(FinalCall) // ONLY at FinalCall, no point calling twice
5320  {
5321  CalcHLocMinEtc(7);
5322  }
5323  Utilities->CallLogPop(1130);
5324  return(true);
5325 }
5326 
5327 // ---------------------------------------------------------------------------
5328 
5329 bool TTrack::IsTrackLinked(int Caller) // not used any more
5330 {
5331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5332  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5333  {
5334  if(TrackElementAt(1290, x).TrackType == Erase)
5335  {
5336  Utilities->CallLogPop(498);
5337  return(false);
5338  }
5339 // check foot linkages
5340  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5341  {
5342  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5343  {
5344  Utilities->CallLogPop(499);
5345  return(false);
5346  }
5347  }
5348  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5349  {
5350  if(TrackElementAt(1293, x).Link[y] <= 0)
5351  {
5352  continue; // no link
5353  }
5354  if(TrackElementAt(1294, x).Config[y] == End)
5355  {
5356  continue; // buffer or continuation
5357  }
5358  if(TrackElementAt(1295, x).Config[y] == Gap)
5359  {
5360  continue; // gaps set later from GapMap
5361 
5362  }
5363  // get required H & V for track element joining link 'y'
5364  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5365  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5366  // find track element if present
5367  bool ConnectionFoundFlag = false;
5368  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5369  if(ConnectionFoundFlag)
5370  {
5371  TrackElementAt(1300, x).Conn[y] = VecPos;
5372  // find connecting link in the newly found track element if there is one & make buffer check
5373  bool LinkFoundFlag = false;
5374  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5375  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5376  {
5377  Utilities->CallLogPop(500);
5378  return(false);
5379  }
5380  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5381  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5382  {
5383  Utilities->CallLogPop(501);
5384  return(false);
5385  }
5386  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5387  {
5388  Utilities->CallLogPop(502);
5389  return(false);
5390  }
5391  else
5392  {
5393  for(unsigned int a = 0; a < 4; a++)
5394  {
5395  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5396  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5397  {
5398  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5399  // note - this ensures that if the connecting element is a leading point
5400  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5401  // (Points have the same link value for both [0] and [2])
5402  LinkFoundFlag = true;
5403  break; // stop after first find or will find later link for leading point
5404  }
5405  }
5406  }
5407  if(!LinkFoundFlag)
5408  {
5409  Utilities->CallLogPop(503);
5410  return(false);
5411  }
5412  }
5413  else // if(ConnectionFoundFlag)
5414  {
5415  Utilities->CallLogPop(504);
5416  return(false);
5417  }
5418  }
5419  } // for(unsigned int x=0;x<TrackVector.size();x++)
5420 
5421 // final check
5422  bool ConnErrorFlag = false;
5423 
5424  for(unsigned int x = 0; x < TrackVector.size(); x++)
5425  {
5426  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5427  {
5428  ConnErrorFlag = true;
5429  }
5430  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5431  {
5432  ConnErrorFlag = true;
5433  }
5434  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5435  {
5436  ConnErrorFlag = true;
5437  }
5438  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5439  {
5440  ConnErrorFlag = true;
5441  }
5442  }
5443  if(ConnErrorFlag)
5444  {
5445  Utilities->CallLogPop(505);
5446  return(false);
5447  }
5448  bool CLkErrorFlag = false;
5449 
5450  for(unsigned int x = 0; x < TrackVector.size(); x++)
5451  {
5452  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5453  {
5454  CLkErrorFlag = true;
5455  }
5456  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5457  {
5458  CLkErrorFlag = true;
5459  }
5460  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5461  {
5462  CLkErrorFlag = true;
5463  }
5464  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5465  {
5466  CLkErrorFlag = true;
5467  }
5468  }
5469 
5470  if(CLkErrorFlag)
5471  {
5472  Utilities->CallLogPop(506);
5473  return(false);
5474  }
5475  Utilities->CallLogPop(507);
5476  return(true);
5477 }
5478 
5479 // ---------------------------------------------------------------------------
5480 
5482 {
5483  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5484  int Position1, Position2;
5485  TTrackElement TrackElement1, TrackElement2;
5486  TGapMapIterator GapMapPtr;
5487 
5488  if(!GapMap.empty())
5489  {
5490  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5491  {
5492  int HLoc1 = GapMapPtr->first.first;
5493  int VLoc1 = GapMapPtr->first.second;
5494  int HLoc2 = GapMapPtr->second.first;
5495  int VLoc2 = GapMapPtr->second.second;
5496  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5497  {
5498  throw Exception("Failed to find H & V for gap1, GapMap in error");
5499  }
5500  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5501  {
5502  throw Exception("Failed to find H & V for gap2, GapMap in error");
5503  }
5504  if(TrackElementAt(9, Position1).TrackType != GapJump)
5505  {
5506  throw Exception("Element at Pos1 not a gap, GapMap in error");
5507  }
5508  if(TrackElementAt(10, Position2).TrackType != GapJump)
5509  {
5510  throw Exception("Element at Pos2 not a gap, GapMap in error");
5511  }
5512  TrackElementAt(11, Position1).Conn[0] = Position2;
5513  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5514  TrackElementAt(13, Position2).Conn[0] = Position1;
5515  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5516  }
5517  }
5518  Utilities->CallLogPop(510);
5519  return(true);
5520 }
5521 
5522 // ---------------------------------------------------------------------------
5523 
5524 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5525 {
5526 // TIMPair MapEntry;
5527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5528  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5529  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5530  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5531  TLocationNameMultiMapEntry LocationNameEntry;
5532 
5533  LocationNameEntry.first = TrackElement.LocationName;
5534  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5535  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5536  {
5537 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5538 // could arise when loading old railways with multiple NonStationNamedLocs
5539  bool FoundFlag = false;
5540  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5541  if(FoundFlag)
5542  {
5543  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5544  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5545  {
5546  Utilities->CallLogPop(1813);
5547  return;
5548  }
5549  }
5550  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5551  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5552  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5553  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5554  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5555  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5556  if(TrackElement.FixedNamedLocationElement)
5557  {
5558  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5559  LocationNameMultiMap.insert(LocationNameEntry);
5560  }
5561  if(TrackElement.HLoc < HLocMin)
5562  {
5563  HLocMin = TrackElement.HLoc;
5564  }
5565  if(TrackElement.HLoc > HLocMax)
5566  {
5567  HLocMax = TrackElement.HLoc;
5568  }
5569  if(TrackElement.VLoc < VLocMin)
5570  {
5571  VLocMin = TrackElement.VLoc;
5572  }
5573  if(TrackElement.VLoc > VLocMax)
5574  {
5575  VLocMax = TrackElement.VLoc;
5576  }
5577  }
5578  else
5579  {
5580 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5581 // shouldn't arise but leave in as a safeguard
5582  bool FoundFlag = false;
5583  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5584  if(FoundFlag)
5585  {
5586  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5587  {
5588  Utilities->CallLogPop(1814);
5589  return;
5590  }
5591  }
5592  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5593  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5594  {
5595  TrackMapKeyPair.first = TrackElement.HLoc;
5596  TrackMapKeyPair.second = TrackElement.VLoc;
5597  TrackMapEntry.first = TrackMapKeyPair;
5598  TrackMapEntry.second = TrackVector.size() - 1;
5599  TrackMap.insert(TrackMapEntry);
5600  if(TrackElement.FixedNamedLocationElement)
5601  {
5602  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5603  LocationNameMultiMap.insert(LocationNameEntry);
5604  }
5605  if(TrackElement.HLoc < HLocMin)
5606  {
5607  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5608  }
5609  if(TrackElement.HLoc > HLocMax)
5610  {
5611  HLocMax = TrackElement.HLoc;
5612  }
5613  if(TrackElement.VLoc < VLocMin)
5614  {
5615  VLocMin = TrackElement.VLoc;
5616  }
5617  if(TrackElement.VLoc > VLocMax)
5618  {
5619  VLocMax = TrackElement.VLoc;
5620  }
5621  }
5622  }
5623 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5624 // CheckMapAndInactiveTrack(6);//test
5625 
5626 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5627 // with the Platforms until layout fully loaded
5628  Utilities->CallLogPop(511);
5629 }
5630 
5631 // ---------------------------------------------------------------------------
5632 
5633 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5634 {
5635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5636  AnsiString(VLoc));
5637  THVPair TrackMapKeyPair;
5638 
5639  FoundFlag = false;
5640  TTrackMapIterator TrackMapPtr;
5641 
5642  TrackMapKeyPair.first = HLoc;
5643  TrackMapKeyPair.second = VLoc;
5644  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5645  if(TrackMapPtr == TrackMap.end())
5646  {
5647  Utilities->CallLogPop(512);
5648  return(-1); // nothing found
5649  }
5650  else
5651  {
5652  FoundFlag = true;
5653  Utilities->CallLogPop(513);
5654  return(TrackMapPtr->second);
5655  }
5656 }
5657 
5658 // ---------------------------------------------------------------------------
5659 
5660 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5661 {
5662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5663  AnsiString(VLoc));
5664  THVPair TrackMapKeyPair;
5665  TTrackMapIterator TrackMapPtr;
5666 
5667  TrackMapKeyPair.first = HLoc;
5668  TrackMapKeyPair.second = VLoc;
5669  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5670  if(TrackMapPtr == TrackMap.end())
5671  {
5672  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5673  throw Exception(Message);
5674  }
5675  else
5676  {
5677  Utilities->CallLogPop(1943);
5678  return(TrackElementAt(871, TrackMapPtr->second));
5679  }
5680 }
5681 
5682 // ---------------------------------------------------------------------------
5683 
5684 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5685 { //modded at v2.9.2 to make Map & Vector references
5686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5687  AnsiString(VLoc));
5688  THVPair MapKeyPair;
5689  TTrackMapIterator MapPtr;
5690 
5691  MapKeyPair.first = HLoc;
5692  MapKeyPair.second = VLoc;
5693  MapPtr = Map.find(MapKeyPair);
5694  if(MapPtr == Map.end())
5695  {
5696  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5697  throw Exception(Message);
5698  }
5699  else
5700  {
5701  Utilities->CallLogPop(2280);
5702  return(Vector.at(MapPtr->second));
5703  }
5704 }
5705 
5706 // ---------------------------------------------------------------------------
5707 
5709 {
5710  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5711  AnsiString(VLoc));
5712  THVPair InactiveTrackMapKeyPair;
5713  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5714 
5715  InactiveTrackMapKeyPair.first = HLoc;
5716  InactiveTrackMapKeyPair.second = VLoc;
5717  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5718  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5719  {
5720  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5721  throw Exception(Message);
5722  }
5723  else
5724  {
5725  Utilities->CallLogPop(1949);
5726  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5727  }
5728 }
5729 
5730 // ---------------------------------------------------------------------------
5731 
5732 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5733 {
5734  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5735  bool Present = true;
5736  THVPair TrackMapKeyPair;
5737  TTrackMapIterator TrackMapPtr;
5738 
5739  TrackMapKeyPair.first = HLoc;
5740  TrackMapKeyPair.second = VLoc;
5741  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5742  if(TrackMapPtr == TrackMap.end())
5743  {
5744  Present = false;
5745  }
5746  Utilities->CallLogPop(2057);
5747  return(Present);
5748 }
5749 
5750 // ---------------------------------------------------------------------------
5751 
5752 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5753 {
5754  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5755  AnsiString(VLoc));
5756  bool Present = true;
5757  THVPair InactiveTrackMapKeyPair;
5758  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5759 
5760  InactiveTrackMapKeyPair.first = HLoc;
5761  InactiveTrackMapKeyPair.second = VLoc;
5762  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5763  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5764  {
5765  Present = false;
5766  }
5767  Utilities->CallLogPop(2058);
5768  return(Present);
5769 }
5770 
5771 // ---------------------------------------------------------------------------
5772 
5773 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5774 // max number of elements is 2, for platforms
5775 // note that both elements of RetPair may be the same, if only one present in map
5776 {
5777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5778  AnsiString(VLoc));
5779  THVPair InactiveTrackMapKeyPair;
5780  TIMPair RetPair;
5781  TInactiveTrackRange InactiveTrackRange;
5782 
5783  FoundFlag = false;
5784  InactiveTrackMapKeyPair.first = HLoc;
5785  InactiveTrackMapKeyPair.second = VLoc;
5786  if(InactiveTrack2MultiMap.empty())
5787  {
5788  RetPair.first = 0;
5789  RetPair.second = 0;
5790  Utilities->CallLogPop(1815);
5791  return(RetPair); // map empty
5792  }
5793  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5794  if(InactiveTrackRange.first == InactiveTrackRange.second)
5795  {
5796  RetPair.first = 0;
5797  RetPair.second = 0;
5798  Utilities->CallLogPop(514);
5799  return(RetPair); // nothing found
5800  }
5801  else
5802  {
5803  RetPair.first = InactiveTrackRange.first->second;
5804  RetPair.second = (--InactiveTrackRange.second)->second;
5805  FoundFlag = true;
5806  Utilities->CallLogPop(515);
5807  return(RetPair);
5808  }
5809 }
5810 
5811 // ---------------------------------------------------------------------------
5812 
5813 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5814 {
5815 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5817  AnsiString(DivergingPosition));
5818  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5819  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5820  int SpeedTag1 = T1.SpeedTag;
5821  int SpeedTag2 = T2.SpeedTag;
5822 
5823  if(T1.Attribute != T2.Attribute)
5824  {
5825  Utilities->CallLogPop(516);
5826  return(false);
5827  }
5828  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5829  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5830  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5831  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5832  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5833  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5834  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5835  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5836  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5837  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5838  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5839  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5840  {
5841  Utilities->CallLogPop(517);
5842  return(true);
5843  }
5844  else
5845  {
5846  Utilities->CallLogPop(518);
5847  return(false);
5848  }
5849 }
5850 
5851 // ---------------------------------------------------------------------------
5852 
5853 /*
5854  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5855  {
5856  if(lower.second < higher.second) return true;
5857  else if(lower.second > higher.second) return false;
5858  else if(lower.second == higher.second)
5859  {
5860  if(lower.first < higher.first) return true;
5861  }
5862  return false;
5863  }
5864 */
5865 // ---------------------------------------------------------------------------
5866 
5867 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5868 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5869 {
5870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5871  if(TrackElement.TrackType != GapJump)
5872  {
5873  throw Exception("Error, Wrong track type in PlotGap");
5874  }
5875  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5876  {
5877  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5878  }
5879  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5880  {
5881  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5882  }
5883  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5884  {
5885  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5886  }
5887  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5888  {
5889  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5890  }
5891  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5892  {
5893  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5894  }
5895  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5896  {
5897  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5898  }
5899  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5900  {
5901  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5902  }
5903  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5904  {
5905  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5906  }
5907  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5908  {
5909  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5910  }
5911  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5912  {
5913  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5914  }
5915  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5916  {
5917  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5918  }
5919  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5920  {
5921  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5922  }
5923  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5924  {
5925  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5926  }
5927  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5928  {
5929  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5930  }
5931  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5932  {
5933  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5934  }
5935  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5936  {
5937  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5938  }
5939  Utilities->CallLogPop(1101);
5940 }
5941 
5942 // ---------------------------------------------------------------------------
5943 
5944 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
5945 {
5946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
5947  TrackElement.PlotVariableTrackElement(7, Disp);
5948  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
5949  {
5950  THVPair PosPair;
5951  PosPair.first = TrackElement.HLoc;
5952  PosPair.second = TrackElement.VLoc;
5953  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
5954  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
5955  {
5956  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
5957  }
5958  }
5959  Utilities->CallLogPop(2403);
5960 }
5961 
5962 // ---------------------------------------------------------------------------
5963 
5964 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5965 {
5966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5967  if(TrackElement.TrackType != Points)
5968  {
5969  throw Exception("Error, Wrong track type in PlotPoints");
5970  }
5971  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5972  TrackElement.PlotVariableTrackElement(4, Disp);
5973  if(BothFillets)
5974  {
5975  if(TrackElement.SpeedTag < 28)
5976  {
5977  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5978  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5979  }
5980  else if(TrackElement.SpeedTag < 132)
5981  {
5982  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5983  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5984  }
5985  else
5986  {
5987  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5988  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5989  }
5990  }
5991  else
5992  {
5993  if(TrackElement.SpeedTag < 28)
5994  {
5995  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5996  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5997  }
5998  else if(TrackElement.SpeedTag < 132)
5999  {
6000  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6001  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
6002  }
6003  else
6004  {
6005  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6006  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
6007  }
6008  }
6009 // replot platform if required
6010  TIMPair IMPair;
6011  bool FoundFlag;
6012 
6013  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6014  if(FoundFlag)
6015  {
6016  // only one platform possible at points so only need to plot IMPair.first
6017  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6018  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6019  }
6020  Utilities->CallLogPop(519);
6021 }
6022 
6023 // ---------------------------------------------------------------------------
6024 
6025 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6026 {
6027 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6028  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6029  if(TrackElement.TrackType != SignalPost)
6030  {
6031  throw Exception("Error, Wrong track type in PlotSignal");
6032  }
6033  for(int x = 0; x < 40; x++)
6034  {
6035  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6036  {
6037  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6038  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6039 // in case existing signal is a double yellow
6040  // plot platforms if present
6041 // Graphics::TBitmap* SignalPlatformGraphic;
6042 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6043 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6044 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6045 // to not be plotted with the above function.
6046  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6047  // now plot signal (double yellow overwrites most of signal platform if present)
6048  // additions at version 0.6 for other aspects & ground sigs
6049  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6050  {
6051  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6052  }
6053  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6054  {
6055  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6056  }
6057  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6058  {
6059  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6060  }
6061  else // 4 aspect
6062  {
6063  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6064  }
6065  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6066  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6067  {
6068  if(TrackElement.SpeedTag == 68)
6069  {
6070  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6071  }
6072  if(TrackElement.SpeedTag == 69)
6073  {
6074  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6075  }
6076  if(TrackElement.SpeedTag == 70)
6077  {
6078  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6079  }
6080  if(TrackElement.SpeedTag == 71)
6081  {
6082  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6083  }
6084  if(TrackElement.SpeedTag == 72)
6085  {
6086  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6087  }
6088  if(TrackElement.SpeedTag == 73)
6089  {
6090  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6091  }
6092  if(TrackElement.SpeedTag == 74)
6093  {
6094  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6095  }
6096  if(TrackElement.SpeedTag == 75)
6097  {
6098  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6099  }
6100  }
6101  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6102  // ground signal calling on, need to use normal proceed aspect
6103  {
6104  for(int x = 0; x < 40; x++)
6105  {
6106  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6107  {
6108  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6109  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6110  // plot special signal platform if present
6111  Graphics::TBitmap* SignalPlatformGraphic;
6112  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6113  // now plot signal
6114  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6115  }
6116  }
6117  }
6118  break;
6119  }
6120  }
6121  Utilities->CallLogPop(520);
6122 }
6123 
6124 // ---------------------------------------------------------------------------
6125 
6126 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6127 {
6128  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6129  bool FoundFlag;
6130  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6131 
6132  if(!FoundFlag)
6133  {
6134  Utilities->CallLogPop(2112);
6135  return;
6136  }
6137  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6138  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6139 
6140  // don't want 'else if' for the below as may need to plot 2 platforms
6141  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6142  {
6143  if(IAElement1.LocationName == "") // '2' will be same
6144  {
6145  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6146  }
6147  else
6148  {
6149  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6150  }
6151  }
6152  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6153  {
6154  if(IAElement1.LocationName == "") // '2' will be same
6155  {
6156  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6157  }
6158  else
6159  {
6160  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6161  }
6162  }
6163  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6164  {
6165  if(IAElement1.LocationName == "") // '2' will be same
6166  {
6167  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6168  }
6169  else
6170  {
6171  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6172  }
6173  }
6174  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6175  {
6176  if(IAElement1.LocationName == "") // '2' will be same
6177  {
6178  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6179  }
6180  else
6181  {
6182  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6183  }
6184  }
6185  Utilities->CallLogPop(2113);
6186 }
6187 
6188 // ---------------------------------------------------------------------------
6189 
6190 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6191 {
6192 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6193  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6194  AnsiString(VLoc));
6195 // find topmost LC, opening them all (to trains) in turn
6196  int UpStep = 0;
6197 
6198  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6199  {
6200  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6201  UpStep--;
6202  }
6203 // now find bottommost LC, opening them all (to trains) in turn
6204  int DownStep = 1;
6205 
6206  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6207  {
6208  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6209  DownStep++;
6210  }
6211 // find leftmost LC, opening them all (to trains) in turn
6212  int LeftStep = 0;
6213 
6214  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6215  {
6216  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6217  LeftStep--;
6218  }
6219 // now find rightmost LC, opening them all (to trains) in turn
6220  int RightStep = 1;
6221 
6222  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6223  {
6224  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6225  RightStep++;
6226  }
6227  Utilities->CallLogPop(1915);
6228 }
6229 
6230 // ---------------------------------------------------------------------------
6231 
6232 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6233 {
6234  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6235 // work upwards setting all to manual
6236  int UpStep = -1;
6237 
6238  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6239  {
6240  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6241  UpStep--;
6242  }
6243 // work downwards setting all to manual
6244  int DownStep = 1;
6245 
6246  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6247  {
6248  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6249  DownStep++;
6250  }
6251 // work leftwards setting all to manual
6252  int LeftStep = -1;
6253 
6254  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6255  {
6256  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6257  LeftStep--;
6258  }
6259 // work rightwards setting all to manual
6260  int RightStep = 1;
6261 
6262  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6263  {
6264  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6265  RightStep++;
6266  }
6267  Utilities->CallLogPop(2242);
6268 }
6269 
6270 // ---------------------------------------------------------------------------
6271 
6272 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6273 {
6274  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6275  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6276  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6277  {
6278  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6279  {
6280  BarriersDownVector.at(x).TypeOfRoute = 2;
6281  break;
6282  }
6283  }
6284  Utilities->CallLogPop(2243);
6285 }
6286 
6287 // ---------------------------------------------------------------------------
6288 
6289 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6290 {
6291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6292 // work upwards
6293  int UpStep = 0; //start with this location
6294 
6295  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6296  {
6297  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6298  {
6299  Utilities->CallLogPop(2244);
6300  return(true);
6301  }
6302  UpStep--;
6303  }
6304 // work downwards
6305  int DownStep = 1;
6306 
6307  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6308  {
6309  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6310  {
6311  Utilities->CallLogPop(2245);
6312  return(true);
6313  }
6314  DownStep++;
6315  }
6316 // work leftwards
6317  int LeftStep = -1;
6318 
6319  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6320  {
6321  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6322  {
6323  Utilities->CallLogPop(2246);
6324  return(true);
6325  }
6326  LeftStep--;
6327  }
6328 // work rightwards
6329  int RightStep = 1;
6330 
6331  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6332  {
6333  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6334  {
6335  Utilities->CallLogPop(2247);
6336  return(true);
6337  }
6338  RightStep++;
6339  }
6340  Utilities->CallLogPop(2248);
6341  return(false);
6342 }
6343 
6344 // ---------------------------------------------------------------------------
6345 
6346 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6347 {
6348  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6349  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6350  {
6351  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6352  {
6353  BDVectorPos = x;
6354  Utilities->CallLogPop(2249);
6355  return(true);
6356  }
6357  }
6358  BDVectorPos = -1;
6359  Utilities->CallLogPop(2250);
6360  return(false);
6361 }
6362 
6363 // ---------------------------------------------------------------------------
6364 
6365 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6366 // open to trains
6367 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6368 {
6369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6370  AnsiString(VLoc));
6371  if(!IsLCAtHV(4, HLoc, VLoc))
6372  {
6373  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6374  }
6375  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6376  {
6377  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6378  }
6379 // check for adjacent LCs & if so open (to trains)
6380  if(BaseElementSpeedTag == 1) // hor track element
6381  {
6382  // find topmost LC, opening them all (to trains) in turn
6383  int UpStep = 0;
6384  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6385  {
6386  UpStep--;
6387  }
6388  UpStep++;
6389  // now find bottommost LC, opening them all (to trains) in turn
6390  int DownStep = 1;
6391  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6392  {
6393  DownStep++;
6394  }
6395  DownStep--;
6396  // now plot graphics, UpStep is smallest & DownStep largest
6397  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6398  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6399  Graphics::TBitmap *RouteGraphic;
6400  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6401  if(TypeOfRoute == 1)
6402  {
6403  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6404  }
6405  else if(TypeOfRoute == 0)
6406  {
6407  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6408  }
6409  else //manual - no route
6410  {
6411  RouteGraphic = BaseGraphic;
6412  }
6413 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6414 // LinkSigRouteGraphicsPtr[1] ver }
6415 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6416 // LinkNonSigRouteGraphicsPtr[1] ver }
6417 
6418  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6419  {
6420  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6421  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6422  if(!Manual)
6423  {
6424  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6425  }
6426  else
6427  {
6428  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6429  }
6430  }
6431  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6432  {
6433  if(UpStep == 0)
6434  {
6435  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6436  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6437  if(!Manual)
6438  {
6439  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6440  }
6441  else
6442  {
6443  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6444  }
6445  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6446  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6447  if(!Manual)
6448  {
6449  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6450  }
6451  else
6452  {
6453  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6454  }
6455  }
6456  else
6457  {
6458  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6459  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6460  if(!Manual)
6461  {
6462  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6463  }
6464  else
6465  {
6466  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6467  }
6468  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6469  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6470  if(!Manual)
6471  {
6472  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6473  }
6474  else
6475  {
6476  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6477  }
6478  }
6479  }
6480  else // at least one plain graphic
6481  {
6482  if(UpStep == 0)
6483  {
6484  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6485  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6486  if(!Manual)
6487  {
6488  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6489  }
6490  else
6491  {
6492  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6493  }
6494  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6495  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6496  if(!Manual)
6497  {
6498  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6499  }
6500  else
6501  {
6502  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6503  }
6504  }
6505  else if(DownStep == 0)
6506  {
6507  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6508  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6509  if(!Manual)
6510  {
6511  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6512  }
6513  else
6514  {
6515  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6516  }
6517  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6518  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6519  if(!Manual)
6520  {
6521  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6522  }
6523  else
6524  {
6525  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6526  }
6527  }
6528  else
6529  {
6530  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6531  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6532  if(!Manual)
6533  {
6534  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6535  }
6536  else
6537  {
6538  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6539  }
6540  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6541  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6542  if(!Manual)
6543  {
6544  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6545  }
6546  else
6547  {
6548  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6549  }
6550  }
6551  for(int x = (UpStep + 1); x < DownStep; x++)
6552  {
6553  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6554  if(x == 0)
6555  {
6556  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6557  }
6558  else
6559  {
6560  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6561  }
6562  if(!Manual)
6563  {
6564  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6565  }
6566  else
6567  {
6568  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6569  }
6570  }
6571  }
6572  Disp->Update();
6573  Utilities->CallLogPop(1958);
6574  return;
6575  }
6576 
6577  else // ver track element
6578  {
6579  // find leftmost LC, opening them all (to trains) in turn
6580  int LStep = 0;
6581  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6582  {
6583  LStep--;
6584  }
6585  LStep++;
6586  // now find rightmost LC, opening them all (to trains) in turn
6587  int RStep = 1;
6588  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6589  {
6590  RStep++;
6591  }
6592  RStep--;
6593  // now plot graphics, LStep is smallest & RStep largest
6594  Graphics::TBitmap *RouteGraphic;
6595  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6596  if(TypeOfRoute == 1)
6597  {
6598  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6599  }
6600  else if(TypeOfRoute == 0)
6601  {
6602  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6603  }
6604  else //manual
6605  {
6606  RouteGraphic = BaseGraphic;
6607  }
6608 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6609 // LinkSigRouteGraphicsPtr[1] ver }
6610 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6611 // LinkNonSigRouteGraphicsPtr[1] ver }
6612  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6613  {
6614  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6615  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6616  if(!Manual)
6617  {
6618  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6619  }
6620  else
6621  {
6622  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6623  }
6624  }
6625  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6626  {
6627  if(LStep == 0)
6628  {
6629  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6630  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6631  if(!Manual)
6632  {
6633  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6634  }
6635  else
6636  {
6637  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6638  }
6639  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6640  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6641  if(!Manual)
6642  {
6643  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6644  }
6645  else
6646  {
6647  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6648  }
6649  }
6650  else
6651  {
6652  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6653  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6654  if(!Manual)
6655  {
6656  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6657  }
6658  else
6659  {
6660  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6661  }
6662  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6663  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6664  if(!Manual)
6665  {
6666  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6667  }
6668  else
6669  {
6670  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6671  }
6672  }
6673  }
6674  else // at least one plain graphic
6675  {
6676  if(LStep == 0)
6677  {
6678  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6679  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6680  if(!Manual)
6681  {
6682  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6683  }
6684  else
6685  {
6686  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6687  }
6688  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6689  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6690  if(!Manual)
6691  {
6692  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6693  }
6694  else
6695  {
6696  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6697  }
6698  }
6699  else if(RStep == 0)
6700  {
6701  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6702  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6703  if(!Manual)
6704  {
6705  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6706  }
6707  else
6708  {
6709  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6710  }
6711  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6712  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6713  if(!Manual)
6714  {
6715  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6716  }
6717  else
6718  {
6719  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6720  }
6721  }
6722  else
6723  {
6724  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6725  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6726  if(!Manual)
6727  {
6728  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6729  }
6730  else
6731  {
6732  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6733  }
6734  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6735  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6736  if(!Manual)
6737  {
6738  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6739  }
6740  else
6741  {
6742  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6743  }
6744  }
6745  for(int x = (LStep + 1); x < RStep; x++)
6746  {
6747  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6748  if(x == 0)
6749  {
6750  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6751  }
6752  else
6753  {
6754  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6755  }
6756  if(!Manual)
6757  {
6758  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6759  }
6760  else
6761  {
6762  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6763  }
6764  }
6765  }
6766  Disp->Update();
6767  Utilities->CallLogPop(1896);
6768  return;
6769  }
6770 }
6771 
6772 // ---------------------------------------------------------------------------
6773 
6774 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6775 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6776 {
6777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6778  AnsiString(HLoc) + "," + AnsiString(VLoc));
6779  if(!IsLCAtHV(29, HLoc, VLoc))
6780  {
6781  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6782  }
6783  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6784  {
6785  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6786  }
6787 // check for adjacent LCs & if so open (to trains)
6788  if(BaseElementSpeedTag == 1) // hor track element
6789  {
6790  // find topmost LC, opening them all (to trains) in turn
6791  int UpStep = 0;
6792  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6793  {
6794  UpStep--;
6795  }
6796  UpStep++;
6797  // now find bottommost LC, opening them all (to trains) in turn
6798  int DownStep = 1;
6799  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6800  {
6801  DownStep++;
6802  }
6803  DownStep--;
6804  // now plot graphics, UpStep is smallest & DownStep largest
6805  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6806  {
6807  if(!Manual)
6808  {
6809  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6810  }
6811  else
6812  {
6813  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6814  }
6815  }
6816  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6817  {
6818  if(!Manual)
6819  {
6820  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6821  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6822  }
6823  else
6824  {
6825  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6826  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6827  }
6828  }
6829  else // at least one plain graphic
6830  {
6831  if(!Manual)
6832  {
6833  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6834  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6835  for(int x = (UpStep + 1); x < DownStep; x++)
6836  {
6837  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6838  }
6839  }
6840  else
6841  {
6842  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6843  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6844  for(int x = (UpStep + 1); x < DownStep; x++)
6845  {
6846  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6847  }
6848  }
6849  }
6850  // set markers
6851  for(int x = UpStep; x <= DownStep; x++)
6852  {
6853  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6854  }
6855  Display->Update();
6856  Utilities->CallLogPop(1944);
6857  return;
6858  }
6859 
6860  else // ver track element
6861  {
6862  // find leftmost LC, opening them all (to trains) in turn
6863  int LStep = 0;
6864  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6865  {
6866  LStep--;
6867  }
6868  LStep++;
6869  // now find rightmost LC, opening them all (to trains) in turn
6870  int RStep = 1;
6871  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6872  {
6873  RStep++;
6874  }
6875  RStep--;
6876  // now plot graphics, LStep is smallest & RStep largest
6877  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6878  {
6879  if(!Manual)
6880  {
6881  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6882  }
6883  else
6884  {
6885  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6886  }
6887  }
6888  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6889  {
6890  if(!Manual)
6891  {
6892  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6893  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6894  }
6895  else
6896  {
6897  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6898  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6899  }
6900  }
6901  else // at least one plain graphic
6902  {
6903  if(!Manual)
6904  {
6905  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6906  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6907  for(int x = (LStep + 1); x < RStep; x++)
6908  {
6909  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6910  }
6911  }
6912  else
6913  {
6914  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6915  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6916  for(int x = (LStep + 1); x < RStep; x++)
6917  {
6918  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6919  }
6920  }
6921  }
6922  // set markers
6923  for(int x = LStep; x <= RStep; x++)
6924  {
6925  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6926  }
6927  Disp->Update();
6928  Utilities->CallLogPop(1945);
6929  return;
6930  }
6931 }
6932 
6933 // ---------------------------------------------------------------------------
6934 
6935 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6936 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6937 {
6938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6939  AnsiString(VLoc));
6940  if(!IsLCAtHV(9, HLoc, VLoc))
6941  {
6942  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6943  }
6944  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6945  {
6946  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6947  }
6948 // check for adjacent LCs & if so close (to trains)
6949  if(BaseElementSpeedTag == 1) // hor track element
6950  {
6951  // find topmost LC, closing them all (to trains) in turn
6952  int UpStep = 0;
6953  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6954  {
6955  UpStep--;
6956  }
6957  UpStep++;
6958  // now find bottommost LC, opening them all (to trains) in turn
6959  int DownStep = 1;
6960  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6961  {
6962  DownStep++;
6963  }
6964  DownStep--;
6965  // now plot graphics, UpStep is smallest & DownStep largest
6966  for(int x = UpStep; x < (DownStep + 1); x++)
6967  {
6968  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6969  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6970  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6971  }
6972  Disp->Update();
6973  Utilities->CallLogPop(1959);
6974  return;
6975  }
6976 
6977  else // ver track element
6978  {
6979  // find leftmost LC, closing them all (to trains) in turn
6980  int LStep = 0;
6981  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6982  {
6983  LStep--;
6984  }
6985  LStep++;
6986  // now find rightmost LC, opening them all (to trains) in turn
6987  int RStep = 1;
6988  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6989  {
6990  RStep++;
6991  }
6992  RStep--;
6993  // now plot graphics, LStep is smallest & RStep largest
6994  for(int x = LStep; x < (RStep + 1); x++)
6995  {
6996  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6997  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6998  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6999  }
7000  Disp->Update();
7001  Utilities->CallLogPop(1960);
7002  return;
7003  }
7004 }
7005 
7006 // ---------------------------------------------------------------------------
7007 
7008 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7009 // closed to trains
7010 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7011 {
7012  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7013  AnsiString(HLoc) + "," + AnsiString(VLoc));
7014  if(!IsLCAtHV(34, HLoc, VLoc))
7015  {
7016  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7017  }
7018  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7019  {
7020  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7021  }
7022  TTrackElement TE;
7023 
7024 // check for adjacent LCs & if so close (to trains)
7025  if(BaseElementSpeedTag == 1) // hor track element
7026  {
7027  // find topmost LC, closing them all (to trains) in turn
7028  int UpStep = 0;
7029  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7030  {
7031  UpStep--;
7032  }
7033  UpStep++;
7034  // now find bottommost LC, opening them all (to trains) in turn
7035  int DownStep = 1;
7036  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7037  {
7038  DownStep++;
7039  }
7040  DownStep--;
7041  // now plot graphics, UpStep is smallest & DownStep largest
7042  for(int x = UpStep; x <= DownStep; x++)
7043  {
7044  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7045  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7046  }
7047  Display->Update();
7048  Utilities->CallLogPop(1946);
7049  return;
7050  }
7051 
7052  else // ver track element
7053  {
7054  // find leftmost LC, closing them all (to trains) in turn
7055  int LStep = 0;
7056  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7057  {
7058  LStep--;
7059  }
7060  LStep++;
7061  // now find rightmost LC, opening them all (to trains) in turn
7062  int RStep = 1;
7063  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7064  {
7065  RStep++;
7066  }
7067  RStep--;
7068  // now plot graphics, LStep is smallest & RStep largest
7069  for(int x = LStep; x <= RStep; x++)
7070  {
7071  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7072  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7073  }
7074  Display->Update();
7075  Utilities->CallLogPop(1947);
7076  return;
7077  }
7078 }
7079 
7080 // ---------------------------------------------------------------------------
7081 
7082 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7083 {
7084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7085  Graphics::TBitmap *RouteGraphic;
7086  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7087 
7088  if(BaseElementSpeedTag == 1)
7089  {
7090  if(TypeOfRoute == 1)
7091  {
7092  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7093  }
7094  else if(TypeOfRoute == 0)
7095  {
7096  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7097  }
7098  else //manual
7099  {
7100  RouteGraphic = BaseGraphic;
7101  }
7102  if(State == Raising)
7103  {
7104  RouteGraphic = BaseGraphic;
7105  }
7106  }
7107  else
7108  {
7109  BaseGraphic = RailGraphics->gl2;
7110  if(TypeOfRoute == 1)
7111  {
7112  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7113  }
7114  else if(TypeOfRoute == 0)
7115  {
7116  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7117  }
7118  else
7119  {
7120  RouteGraphic = BaseGraphic; //manual
7121  }
7122  if(State == Raising)
7123  {
7124  RouteGraphic = BaseGraphic;
7125  }
7126  }
7127  int UpStep = 0;
7128 
7129  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7130  {
7131  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7132  if(UpStep == 0)
7133  {
7134  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7135  }
7136  else
7137  {
7138  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7139  }
7140  UpStep--;
7141  }
7142 // now find bottommost LC, opening them all (to trains) in turn
7143  int DownStep = 1;
7144 
7145  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7146  {
7147  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7148  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7149  DownStep++;
7150  }
7151  int LeftStep = 0;
7152 
7153  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7154  {
7155  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7156  if(LeftStep == 0)
7157  {
7158  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7159  }
7160  else
7161  {
7162  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7163  }
7164  LeftStep--;
7165  }
7166 // now find rightmost LC, opening them all (to trains) in turn
7167  int RightStep = 1;
7168 
7169  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7170  {
7171  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7172  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7173  RightStep++;
7174  }
7175  Disp->Update();
7176  Utilities->CallLogPop(1914);
7177 }
7178 
7179 // ---------------------------------------------------------------------------
7180 
7181 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7182 {
7183 // return false for no LC there, flashing or a closed (to trains) LC
7184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7185  bool FoundFlag;
7186  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7187 
7188  if(!FoundFlag)
7189  {
7190  Utilities->CallLogPop(1898);
7191  return(false);
7192  }
7193  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7194  {
7195  Utilities->CallLogPop(1899);
7196  return(false);
7197  }
7198  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7199  {
7200  Utilities->CallLogPop(1900);
7201  return(true);
7202  }
7203  Utilities->CallLogPop(1901);
7204  return(false);
7205 }
7206 
7207 // ---------------------------------------------------------------------------
7208 
7209 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7210 {
7211 // return false for no LC there, flashing LC or open (to trains) LC
7212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7213  bool FoundFlag;
7214  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7215 
7216  if(!FoundFlag)
7217  {
7218  Utilities->CallLogPop(1922);
7219  return(false);
7220  }
7221  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7222  {
7223  Utilities->CallLogPop(1923);
7224  return(false);
7225  }
7226  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7227  {
7228  Utilities->CallLogPop(1924);
7229  return(true);
7230  }
7231  Utilities->CallLogPop(1925);
7232  return(false);
7233 }
7234 
7235 // ---------------------------------------------------------------------------
7236 
7237 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7238 {
7239 // return true for barrier in process of moving
7240  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7241  bool FoundFlag;
7242  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7243 
7244  if(!FoundFlag)
7245  {
7246  Utilities->CallLogPop(1918);
7247  return(false);
7248  }
7249  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7250  {
7251  Utilities->CallLogPop(1919);
7252  return(false);
7253  }
7254  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7255  {
7256  Utilities->CallLogPop(1920);
7257  return(true);
7258  }
7259  Utilities->CallLogPop(1921);
7260  return(false);
7261 }
7262 
7263 // ---------------------------------------------------------------------------
7264 
7265 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7266 {
7267 // return true for an LC at H&V
7268  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7269  bool FoundFlag;
7270  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7271 
7272  if(!FoundFlag)
7273  {
7274  Utilities->CallLogPop(1902);
7275  return(false);
7276  }
7277  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7278  {
7279  Utilities->CallLogPop(1903);
7280  return(false);
7281  }
7282  Utilities->CallLogPop(1904);
7283  return(true);
7284 }
7285 
7286 // ---------------------------------------------------------------------------
7287 
7288 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7289 {
7290  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7291  AnsiString(Attr));
7292  bool FoundFlag;
7293  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7294 
7295  if(!FoundFlag)
7296  {
7297  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7298  }
7299  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7300  {
7301  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7302  }
7303  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7304  Utilities->CallLogPop(1905);
7305  return;
7306 }
7307 
7308 // ---------------------------------------------------------------------------
7309 
7311 {
7312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7313  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7314  {
7315  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7316  if(InactiveTrackElement.TrackType == LevelCrossing)
7317  {
7318  InactiveTrackElementAt(141, x).Attribute = 0;
7319  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7320  }
7321  }
7322  Utilities->CallLogPop(1913);
7323  return;
7324 }
7325 
7326 // ---------------------------------------------------------------------------
7327 
7328 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7329 {
7330 // return true if there is either a route set or being set on any element or a train on any element
7331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7332  "," + AnsiString(VLoc));
7333 
7334  THVPair TrackMapKeyPair;
7335  TTrack::TTrackMapIterator TrackMapPtr;
7336  int DummyRouteNumber;
7337 
7338  TrainPresent = false;
7339 // find topmost LC, checking each for routes & trains
7340  int UpStep = 0;
7341 
7342  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7343  {
7344  TrackMapKeyPair.first = HLoc;
7345  TrackMapKeyPair.second = VLoc + UpStep;
7346  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7347  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7348  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7349  {
7350  Utilities->CallLogPop(1932);
7351  return(true);
7352  }
7353  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7354  {
7355  TrainPresent = true;
7356  Utilities->CallLogPop(1933);
7357  return(true);
7358  }
7359  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7360  {
7361  Utilities->CallLogPop(2274);
7362  return(true);
7363  }
7364  UpStep--;
7365  }
7366 // now find bottommost LC, opening them all (to trains) in turn
7367  int DownStep = 1;
7368 
7369  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7370  {
7371  TrackMapKeyPair.first = HLoc;
7372  TrackMapKeyPair.second = VLoc + DownStep;
7373  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7374  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7375  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7376  {
7377  Utilities->CallLogPop(1934);
7378  return(true);
7379  }
7380  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7381  {
7382  TrainPresent = true;
7383  Utilities->CallLogPop(1935);
7384  return(true);
7385  }
7386  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7387  {
7388  Utilities->CallLogPop(2275);
7389  return(true);
7390  }
7391  DownStep++;
7392  }
7393 // find leftmost LC
7394  int LeftStep = 0;
7395 
7396  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7397  {
7398  TrackMapKeyPair.first = HLoc + LeftStep;
7399  TrackMapKeyPair.second = VLoc;
7400  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7401  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7402  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7403  {
7404  Utilities->CallLogPop(1936);
7405  return(true);
7406  }
7407  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7408  {
7409  TrainPresent = true;
7410  Utilities->CallLogPop(1937);
7411  return(true);
7412  }
7413  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7414  {
7415  Utilities->CallLogPop(2276);
7416  return(true);
7417  }
7418  LeftStep--;
7419  }
7420 // now find rightmost LC, opening them all (to trains) in turn
7421  int RightStep = 1;
7422 
7423  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7424  {
7425  TrackMapKeyPair.first = HLoc + RightStep;
7426  TrackMapKeyPair.second = VLoc;
7427  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7428  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7429  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7430  {
7431  Utilities->CallLogPop(1938);
7432  return(true);
7433  }
7434  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7435  {
7436  TrainPresent = true;
7437  Utilities->CallLogPop(1939);
7438  return(true);
7439  }
7440  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7441  {
7442  Utilities->CallLogPop(2277);
7443  return(true);
7444  }
7445  RightStep++;
7446  }
7447  Utilities->CallLogPop(1940);
7448  return(false);
7449 }
7450 
7451 // ---------------------------------------------------------------------------
7452 
7453 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7454 {
7455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7456  for(unsigned int x = 0; x < SearchVector.size(); x++)
7457  {
7458  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7459  {
7460  Utilities->CallLogPop(2278);
7461  return(true);
7462  }
7463  }
7464  Utilities->CallLogPop(2279);
7465  return(false);
7466 }
7467 
7468 // ---------------------------------------------------------------------------
7469 
7470 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7471 {
7472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7473  AnsiString(HLoc) + "," + AnsiString(VLoc));
7474  if(!IsLCAtHV(60, HLoc, VLoc))
7475  {
7476  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7477  }
7478 
7479 // check for adjacent LCs
7480  // find topmost LC
7481  int UpStep = 0;
7482  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7483  {
7484  UpStep--;
7485  }
7486  UpStep++;
7487  // now find bottommost LC, opening them all (to trains) in turn
7488  int DownStep = 1;
7489  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7490  {
7491  DownStep++;
7492  }
7493  DownStep--;
7494  // now plot graphics, UpStep is smallest & DownStep largest
7495  for(int x = UpStep; x <= DownStep; x++)
7496  {
7497  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7498  }
7499 
7500  // find leftmost LC, closing them all (to trains) in turn
7501  int LStep = 0;
7502  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7503  {
7504  LStep--;
7505  }
7506  LStep++;
7507  // now find rightmost LC, opening them all (to trains) in turn
7508  int RStep = 1;
7509  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7510  {
7511  RStep++;
7512  }
7513  RStep--;
7514  // now plot graphics, LStep is smallest & RStep largest
7515  for(int x = LStep; x <= RStep; x++)
7516  {
7517  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7518  }
7519  Display->Update();
7520  Utilities->CallLogPop(2315);
7521  return;
7522 }
7523 
7524 // ---------------------------------------------------------------------------
7525 
7526 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7527 {
7528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7529  if(TrackElement.TrackType != Points)
7530  {
7531  throw Exception("Error, Wrong track type in GetFilletGraphic");
7532  }
7533  if(TrackElement.SpeedTag < 28)
7534  {
7535  Utilities->CallLogPop(521);
7536  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7537  }
7538  else if(TrackElement.SpeedTag < 132)
7539  {
7540  Utilities->CallLogPop(522);
7541 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7542  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7543  }
7544  else
7545  {
7546  Utilities->CallLogPop(1537);
7547  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7548  }
7549 }
7550 
7551 // ---------------------------------------------------------------------------
7552 
7554 {
7555  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7556  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7557  {
7558  TrackElementAt(1351, x).TrainIDOnElement = -1;
7561  }
7562  Utilities->CallLogPop(1342);
7563 }
7564 
7565 // ---------------------------------------------------------------------------
7566 
7567 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7568 /*
7569  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7570 */
7571 {
7572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7573  AnsiString(ScreenPosV));
7574  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7575  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7576 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7577  Utilities->CallLogPop(535);
7578 }
7579 
7580 // ---------------------------------------------------------------------------
7581 
7582 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7583 /*
7584  Converts the screen position to the true (without offsets) position
7585 */
7586 {
7587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7588  AnsiString(ScreenPosV));
7589  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7590  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7591  Utilities->CallLogPop(536);
7592 }
7593 
7594 // ---------------------------------------------------------------------------
7595 
7596 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7597 {
7598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7599  AnsiString(VPosTrue));
7600  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7601  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7602  Utilities->CallLogPop(537);
7603 }
7604 
7605 // ---------------------------------------------------------------------------
7606 
7607 void TTrack::CheckMapAndTrack(int Caller) // test
7608 {
7609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7610  int Zeroes = 0;
7611  bool FoundFlag;
7612 
7613  for(unsigned int a = 0; a < TrackVector.size(); a++)
7614  {
7615  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7616  if(CheckElement.SpeedTag == 0)
7617  {
7618  Zeroes++; // zeroed elements not saved in map
7619  }
7620  else
7621  {
7622  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7623  if(!FoundFlag)
7624  {
7625  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7626  " in TrackMap, Caller=" + (AnsiString)Caller);
7627  }
7628  if(MapVecPos != (int)a)
7629  {
7630  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7631  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7632  (AnsiString)Caller);
7633  }
7634  }
7635  }
7636  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7637  {
7638  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7639  " Caller=" + (AnsiString)Caller);
7640  }
7641  Utilities->CallLogPop(538);
7642  return;
7643 }
7644 
7645 // ---------------------------------------------------------------------------
7646 
7647 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7648 {
7649  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7650  bool FoundFlag;
7651  TIMPair InactivePair;
7652 
7653  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7654  {
7655  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7656  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7657  if(!FoundFlag)
7658  {
7659  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7660  " in InactiveMap, Caller=" + (AnsiString)Caller);
7661  }
7662  if((InactivePair.first != a) && (InactivePair.second != a))
7663  {
7664  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7665  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7666  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7667  }
7668  }
7669  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7670  {
7671  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7672  " Caller=" + (AnsiString)Caller);
7673  }
7674  Utilities->CallLogPop(539);
7675 }
7676 
7677 // ---------------------------------------------------------------------------
7678 
7679 void TTrack::CheckGapMap(int Caller) // test
7680 {
7681  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7682  int Position1, Position2;
7683  TTrackElement TrackElement1, TrackElement2;
7684  TGapMapIterator GapMapPtr;
7685 
7686  if(!GapMap.empty())
7687  {
7688  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7689  {
7690  int HLoc1 = GapMapPtr->first.first;
7691  int VLoc1 = GapMapPtr->first.second;
7692  int HLoc2 = GapMapPtr->second.first;
7693  int VLoc2 = GapMapPtr->second.second;
7694  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7695  {
7696  throw Exception("Failed to find H & V for gap1, GapMap in error");
7697  }
7698  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7699  {
7700  throw Exception("Failed to find H & V for gap2, GapMap in error");
7701  }
7702  if(TrackElementAt(17, Position1).TrackType != GapJump)
7703  {
7704  throw Exception("Element at Pos1 not a gap, GapMap in error");
7705  }
7706  if(TrackElementAt(18, Position2).TrackType != GapJump)
7707  {
7708  throw Exception("Element at Pos2 not a gap, GapMap in error");
7709  }
7710  }
7711  }
7712  unsigned int GapCount = 0;
7713 
7714  for(unsigned int a = 0; a < TrackVector.size(); a++)
7715  {
7716  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7717  if(CheckElement.TrackType == GapJump)
7718  {
7719  GapCount++;
7720  }
7721  }
7722  if((GapMap.size() * 2) != GapCount)
7723  {
7724  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7725  (AnsiString)Caller);
7726  }
7727  Utilities->CallLogPop(540);
7728 }
7729 
7730 // ---------------------------------------------------------------------------
7731 
7732 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7733 {
7734  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7735  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7736  {
7737  if(TrackFinished)
7738  {
7739  throw Exception("Error - TrackFinished with erase element still present");
7740  }
7741  Utilities->CallLogPop(541);
7742  return; // erased element, can't set ID
7743  }
7744  AnsiString IDString;
7745 
7746  if(TrackElement.HLoc < 0)
7747  {
7748  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7749  }
7750  else
7751  {
7752  IDString = AnsiString(TrackElement.HLoc) + "-";
7753  }
7754  if(TrackElement.VLoc < 0)
7755  {
7756  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7757  }
7758  else
7759  {
7760  IDString += AnsiString(TrackElement.VLoc);
7761  }
7762  TrackElement.ElementID = IDString;
7763  Utilities->CallLogPop(542);
7764 }
7765 
7766 // ---------------------------------------------------------------------------
7767 
7768 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7769 {
7770 // e.g. "8-13", "00008-13", "N43-N127", etc
7771  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7772  int DelimPos;
7773 
7774  for(int x = 1; x < String.Length() + 1; x++)
7775  {
7776  if(String.IsDelimiter("-", x))
7777  {
7778  DelimPos = x;
7779  break;
7780  }
7781  if(x == String.Length())
7782  {
7783  if(GiveMessages)
7784  {
7785  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7786  }
7787  Utilities->CallLogPop(543);
7788  return(-1);
7789  }
7790  }
7791  if(DelimPos == 1)
7792  {
7793  if(GiveMessages)
7794  {
7795  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7796  }
7797  Utilities->CallLogPop(544);
7798  return(-1);
7799  }
7800  if(DelimPos == String.Length())
7801  {
7802  if(GiveMessages)
7803  {
7804  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7805  }
7806  Utilities->CallLogPop(545);
7807  return(-1);
7808  }
7809  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7810  {
7811  if(GiveMessages)
7812  {
7813  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7814  }
7815  Utilities->CallLogPop(1508);
7816  return(-1);
7817  }
7818  int HLoc, VLoc;
7819 
7820  if(String.SubString(1, 1) != "N")
7821  {
7822  for(int x = 1; x < DelimPos; x++)
7823  {
7824  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7825  {
7826  if(GiveMessages)
7827  {
7828  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7829  }
7830  Utilities->CallLogPop(546);
7831  return(-1);
7832  }
7833  }
7834  }
7835  if(String.SubString(1, 1) == "N")
7836  {
7837  for(int x = 2; x < DelimPos; x++)
7838  {
7839  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7840  {
7841  if(GiveMessages)
7842  {
7843  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7844  }
7845  Utilities->CallLogPop(763);
7846  return(-1);
7847  }
7848  }
7849  }
7850  if(String.SubString(1, 1) == "N")
7851  {
7852  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7853  }
7854  else
7855  {
7856  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7857  }
7858  if(String.SubString(DelimPos + 1, 1) != "N")
7859  {
7860  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7861  {
7862  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7863  {
7864  if(GiveMessages)
7865  {
7866  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7867  }
7868  Utilities->CallLogPop(547);
7869  return(-1);
7870  }
7871  }
7872  }
7873  if(String.SubString(DelimPos + 1, 1) == "N")
7874  {
7875  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7876  {
7877  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7878  {
7879  if(GiveMessages)
7880  {
7881  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7882  }
7883  Utilities->CallLogPop(764);
7884  return(-1);
7885  }
7886  }
7887  }
7888  if(String.SubString(DelimPos + 1, 1) == "N")
7889  {
7890  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7891  }
7892  else
7893  {
7894  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7895  }
7896  THVPair HVPair(HLoc, VLoc);
7897  TTrackMapIterator TrackMapPtr;
7898 
7899  TrackMapPtr = TrackMap.find(HVPair);
7900  if(TrackMapPtr == TrackMap.end())
7901  {
7902  if(GiveMessages)
7903  {
7904  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7905  }
7906  Utilities->CallLogPop(548);
7907  return(-1);
7908  }
7909  Utilities->CallLogPop(549);
7910  return(TrackMapPtr->second);
7911 }
7912 
7913 // ---------------------------------------------------------------------------
7914 
7915 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7916 /*
7917  True for linked properly at both ends
7918 */
7919 {
7920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7921  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7922  int HLoc = TrackElement.HLoc;
7923  int VLoc = TrackElement.VLoc;
7924 
7925  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7926  {
7927  Utilities->CallLogPop(1821);
7928  return(false);
7929  }
7930  if(TrackElement.SpeedTag == 129) // vertical footbridge
7931  {
7932  // check top connection
7933  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7934  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7935  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7936  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7937  {
7938  Utilities->CallLogPop(550);
7939  return(false);
7940  }
7941  // check bottom connection
7942  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7943  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7944  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7945  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7946  {
7947  Utilities->CallLogPop(551);
7948  return(false);
7949  }
7950  }
7951  if(TrackElement.SpeedTag == 145) // vertical underpass
7952  {
7953  // check top connection
7954  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7955  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7956  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7957  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7958  {
7959  Utilities->CallLogPop(2114);
7960  return(false);
7961  }
7962  // check bottom connection
7963  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7964  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7965  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7966  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7967  {
7968  Utilities->CallLogPop(2115);
7969  return(false);
7970  }
7971  }
7972  if(TrackElement.SpeedTag == 130) // hor footbridge
7973  {
7974  // check left connection
7975  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7976  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7977  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7978  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7979  {
7980  Utilities->CallLogPop(552);
7981  return(false);
7982  }
7983  // check right connection
7984  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7985  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7986  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7987  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7988  {
7989  Utilities->CallLogPop(553);
7990  return(false);
7991  }
7992  }
7993  if(TrackElement.SpeedTag == 146) // hor u'pass
7994  {
7995  // check left connection
7996  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7997  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7998  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7999  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8000  {
8001  Utilities->CallLogPop(2116);
8002  return(false);
8003  }
8004  // check right connection
8005  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8006  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8007  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8008  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8009  {
8010  Utilities->CallLogPop(2117);
8011  return(false);
8012  }
8013  }
8014  Utilities->CallLogPop(554);
8015  return(true);
8016 }
8017 
8018 // ---------------------------------------------------------------------------
8019 
8020 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8021 /*
8022  return true if the SpeedTag present in the map at H & V
8023 */
8024 {
8025  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8026  AnsiString(SpeedTag));
8027  if(InactiveTrack2MultiMap.empty())
8028  {
8029  Utilities->CallLogPop(555);
8030  return(false);
8031  }
8032  THVPair HVPair(HLoc, VLoc);
8034  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8035  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8036 
8037  if(HVRange.first == HVRange.second)
8038  {
8039  Utilities->CallLogPop(556);
8040  return(false);
8041  }
8042  else
8043  {
8044  HVIt1 = HVRange.first;
8045  }
8046  TTrackElement Temp1, Temp2; // test
8047 
8048  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8049  if(--HVRange.second != HVRange.first)
8050  {
8051  HVIt2 = HVRange.second;
8052  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8053  }
8054  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8055  HVIt2->second).SpeedTag == SpeedTag)))
8056  {
8057  Utilities->CallLogPop(557);
8058  return(true);
8059  }
8060  else
8061  {
8062  Utilities->CallLogPop(558);
8063  return(false);
8064  }
8065 }
8066 
8067 // ---------------------------------------------------------------------------
8068 
8069 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8070 /*
8071  return true if the SpeedTag present in the map at H & V
8072 */
8073 {
8074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8075  AnsiString(SpeedTag));
8076  if(TrackMap.empty())
8077  {
8078  Utilities->CallLogPop(559);
8079  return(false);
8080  }
8081  THVPair HVPair(HLoc, VLoc);
8082  TTrackMapIterator End = TrackMap.end();
8083  TTrackMapIterator It = End;
8084 
8085  It = TrackMap.find(HVPair);
8086  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8087  {
8088  Utilities->CallLogPop(560);
8089  return(true);
8090  }
8091  else
8092  {
8093  Utilities->CallLogPop(561);
8094  return(false);
8095  }
8096 }
8097 
8098 // ---------------------------------------------------------------------------
8099 
8100 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8101 {
8102 /*
8103  General:
8104  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8105  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8106  a NamedNonStationLocation.
8107  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8108  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8109  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8110  platform at that location).
8111 
8112  Linked named location elements are those explained in TTrack::TTrack()
8113 
8114  Detail:
8115  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8116  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8117  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8118  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8119  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8120  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8121 
8122  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8123  this function a single element should be in the List (normally from the user's selection but can also be from
8124  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8125  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8126  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8127  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8128  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8129  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8130  moves them into the Map. At the end all linked elements are in the Map.
8131 
8132  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8133  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8134  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8135 */
8136 
8137 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8138 // Display->FileDiagnostics(TestString);//test
8139 
8140  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8141  AnsiString TestString1, TestString2; // test
8142 
8143  Track->LNDone2MultiMap.clear();
8144  if(LNPendingList.size() != 1)
8145  {
8146  throw Exception("LNPendingList size not 1 on entry");
8147  }
8148  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8149  while(!LNPendingList.empty())
8150  {
8151  CurrentElementNumber = LNPendingList.front();
8152  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8153  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8154  int H = CurrentElement->HLoc;
8155  int V = CurrentElement->VLoc;
8156  int Tag = CurrentElement->SpeedTag;
8157  if(Tag == 76) // top plat
8158  {
8159  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8160  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8161  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8162  for(int x = 0; x < 25; x++)
8163  {
8164  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8165  {
8166  LNPendingList.insert(LNPendingList.end(), NewElement);
8167  }
8168  }
8169  }
8170  else if(Tag == 77) // bot plat
8171  {
8172  for(int x = 0; x < 25; x++)
8173  {
8174  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8175  {
8176  LNPendingList.insert(LNPendingList.end(), NewElement);
8177  }
8178  }
8179  }
8180  else if(Tag == 78) // l plat
8181  {
8182  for(int x = 0; x < 25; x++)
8183  {
8184  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8185  {
8186  LNPendingList.insert(LNPendingList.end(), NewElement);
8187  }
8188  }
8189  }
8190  else if(Tag == 79) // r plat
8191  {
8192  for(int x = 0; x < 25; x++)
8193  {
8194  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8195  {
8196  LNPendingList.insert(LNPendingList.end(), NewElement);
8197  }
8198  }
8199  }
8200  else if(Tag == 96) // conc
8201  {
8202  for(int x = 0; x < 28; x++)
8203  {
8204  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8205  {
8206  LNPendingList.insert(LNPendingList.end(), NewElement);
8207  }
8208  }
8209  }
8210  else if(Tag == 129) // vert footbridge
8211  {
8212  for(int x = 0; x < 8; x++)
8213  {
8214  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8215  {
8216  LNPendingList.insert(LNPendingList.end(), NewElement);
8217  }
8218  }
8219  }
8220  else if(Tag == 130) // hor footbridge
8221  {
8222  for(int x = 0; x < 8; x++)
8223  {
8224  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8225  {
8226  LNPendingList.insert(LNPendingList.end(), NewElement);
8227  }
8228  }
8229  }
8230  else if(Tag == 131) // named location
8231  {
8232  for(int x = 0; x < 4; x++)
8233  {
8234  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8235  {
8236  LNPendingList.insert(LNPendingList.end(), NewElement);
8237  }
8238  }
8239  }
8240  else if(Tag == 145) // v u'pass
8241  {
8242  for(int x = 0; x < 8; x++)
8243  {
8244  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8245  {
8246  LNPendingList.insert(LNPendingList.end(), NewElement);
8247  }
8248  }
8249  }
8250  else if(Tag == 146) // h u'pass
8251  {
8252  for(int x = 0; x < 8; x++)
8253  {
8254  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8255  {
8256  LNPendingList.insert(LNPendingList.end(), NewElement);
8257  }
8258  }
8259  }
8260  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8261 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8262  if(AddingElements)
8263  {
8264  int HPos, VPos; // not used but needed for FindText function
8265  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8266  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8267  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8268  {
8269  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8270  if((ExistingName != "") && (ExistingName != LocationName))
8271  {
8272  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8273  {
8274  } // name not in LocationNameMultiMap, so don't erase from TextVector
8275  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8276  {
8277  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8278  {
8279  ;
8280  } // condition not used
8281 
8282  }
8283  }
8284  }
8285  }
8286  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8287  // track at that loc
8288  THVPair HVPair(H, V);
8289  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8290  LNDone2MultiMapEntry.first = HVPair;
8291  LNDone2MultiMapEntry.second = LNPendingList.front();
8292  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8293  LNPendingList.erase(LNPendingList.begin());
8294  }
8295 
8296 // search all name multimap for same name where corresponding active elements don't appear in
8297 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8298 
8299  TLocationNameMultiMapIterator SNIterator;
8300  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8301  bool FoundFlag, ErasedFlag = false;
8302 
8303  if(SNRange.first != SNRange.second)
8304  {
8305  SNRange.first--; // now pointing to before the first
8306  SNRange.second--; // now pointing to the last
8307  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8308  {
8309  // Same elements are in Done map as in name map
8310  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8311  {
8312  ErasedFlag = true;
8313  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8314  TVIt->LocationName = "";
8315  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8316  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8317  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8318  {
8319  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8320  if(FoundFlag)
8321  {
8322  TrackElementAt(20, Position).LocationName = "";
8323  TrackElementAt(21, Position).ActiveTrackElementName = "";
8324  }
8325  }
8326  // erase name in name map
8327 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8328  }
8329  }
8330  }
8331  if(ErasedFlag)
8332  {
8334  }
8335  if(TrackFinished)
8336  {
8338  }
8339 // set here as well as in LinkTrack so don't have to link track just because a name added
8340 // if track not finished then will be set when track validated
8341 
8342 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8343 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8344 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8345 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8346 // so the error would be seen.
8347 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8348  std::pair<AnsiString, char>TempMapPair;
8349 
8350  ContinuationNameMap.clear();
8351  for(int x = 0; x < Track->TrackVectorSize(); x++)
8352  {
8353  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8354  {
8355  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8356  TempMapPair.second = 'x'; // unused
8357  ContinuationNameMap.insert(TempMapPair);
8358  }
8359  }
8360 //end of addition
8361  CheckLocationNameMultiMap(1); // test
8362  Utilities->CallLogPop(562);
8363 }
8364 
8365 // ---------------------------------------------------------------------------
8366 
8367 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8368 /*
8369  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8370  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8371 */
8372 {
8373  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8374  AnsiString(SpeedTag));
8375  if(!NamedLocationElementAt(2, HLoc, VLoc))
8376  {
8377  Utilities->CallLogPop(948);
8378  return(false);
8379  }
8380  bool FoundFlag;
8381  int Position = -1;
8382  TIMPair IMPair;
8383 
8384  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8385  {
8386  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8387  if(FoundFlag)
8388  {
8389  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8390  {
8391  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8392  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8393  // don't allow duplicates in either list, or processing takes a lot longer
8394  {
8395  FoundElement = MapPos;
8396  Utilities->CallLogPop(563);
8397  return(true);
8398  }
8399  }
8400  }
8401  }
8402  else
8403  {
8404  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8405  if(FoundFlag)
8406  {
8407  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8408  {
8409  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8410  {
8411  FoundElement = IMPair.first;
8412  Utilities->CallLogPop(564);
8413  return(true);
8414  }
8415  }
8416  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8417  {
8418  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8419  {
8420  FoundElement = IMPair.second;
8421  Utilities->CallLogPop(565);
8422  return(true);
8423  }
8424  }
8425  }
8426  }
8427  Utilities->CallLogPop(566);
8428  return(false);
8429 }
8430 
8431 // ---------------------------------------------------------------------------
8432 
8433 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8434 /*
8435  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8436  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8437  with the new name
8438 */
8439 {
8440  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8441  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8442 
8443  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8444  int HLoc = TrackElement->HLoc;
8445  int VLoc = TrackElement->VLoc;
8446  bool FoundFlag;
8447 
8448  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8449  // only have timetable names for adjacent platforms & named locations
8450  {
8451  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8452  if(FoundFlag)
8453  {
8454  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8455  }
8456  }
8457  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8458 
8459  if(ErrorString != "")
8460  {
8461  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8462  }
8463  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8464  CheckLocationNameMultiMap(2); // test
8465  Utilities->CallLogPop(567);
8466 }
8467 
8468 // ---------------------------------------------------------------------------
8469 
8470 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8471 /*
8472  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8473 */
8474 {
8475  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8476  if(LNDone2MultiMap.empty())
8477  {
8478  Utilities->CallLogPop(568);
8479  return(false);
8480  }
8481  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8482 
8483  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8484  {
8485  if(LNDone2MultiMapIterator->second == MapPos)
8486  {
8487  Utilities->CallLogPop(569);
8488  return(true);
8489  }
8490  }
8491  Utilities->CallLogPop(570);
8492  return(false);
8493 }
8494 
8495 // ---------------------------------------------------------------------------
8496 
8497 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8498 /*
8499  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8500 */
8501 {
8502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8503  if(LNPendingList.empty())
8504  {
8505  Utilities->CallLogPop(571);
8506  return(false);
8507  }
8508  TLNPendingListIterator LNPendingListIterator;
8509 
8510  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8511  {
8512  if(*LNPendingListIterator == MapPos)
8513  {
8514  Utilities->CallLogPop(572);
8515  return(true);
8516  }
8517  }
8518  Utilities->CallLogPop(573);
8519  return(false);
8520 }
8521 
8522 // ---------------------------------------------------------------------------
8523 
8524 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8525 /*
8526  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8527 */
8528 {
8529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8530  THVPair HVPair(HLoc, VLoc);
8531  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8532  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8533 
8534  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8535  {
8536  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8537  {
8538  Utilities->CallLogPop(574);
8539  return(true);
8540  }
8541  }
8542  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8543  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8544  {
8545  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8546  {
8547  Utilities->CallLogPop(575);
8548  return(true);
8549  }
8550  }
8551  Utilities->CallLogPop(576);
8552  return(false);
8553 }
8554 
8555 // ---------------------------------------------------------------------------
8556 
8557 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8558 {
8559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8560  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8561  {
8562  Utilities->CallLogPop(1953);
8563  return(true);
8564  }
8565  Utilities->CallLogPop(1954);
8566  return(false);
8567 }
8568 
8569 // ---------------------------------------------------------------------------
8570 
8571 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8572 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8573 //program and used when try to save as a .rly file
8574 {
8575  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8578  if(LocationNameMultiMap.empty()) //no names so no duplicates
8579  {
8580  Utilities->CallLogPop(2254);
8581  return(false);
8582  }
8583  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8584  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8585  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8586  {
8588  {
8589  if(GiveMessage)
8590  {
8591  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8592  }
8593  Utilities->CallLogPop(2255);
8594  return(true);
8595  }
8596  }
8597  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8598  {
8599  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8600  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8601  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8602  {
8604  {
8605  if(GiveMessage)
8606  {
8607  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8608  }
8609  Utilities->CallLogPop(2256);
8610  return(true);
8611  }
8612  }
8613  }
8614  Utilities->CallLogPop(2257);
8615  return(false); //OK, no duplicates
8616 }
8617 
8618 // ---------------------------------------------------------------------------
8619 
8621 {
8622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8623  THVPair HVPair;
8624  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8625  //for use in the duplicate check
8626  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8627  {
8628  if(LNMMIt->second < 0) //active track element
8629  {
8630  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8631  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8632  }
8633  else //inactive track element
8634  {
8635  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8636  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8637  }
8638  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8639  }
8640  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8641 
8642  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8643  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8644  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8645 
8646  std::list<THVPair> HVLinkedList;
8647 
8648  //set the first value to true and add it to the list
8649  HVPairsLinkedMap.begin()->second = true;
8650  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8651  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8652  //examination
8653  THVPair HVPairUnderExamination;
8654  THVPairsLinkedMap::iterator HVPLMIt;
8655  THVPair HVPairNew;
8656  while(!HVLinkedList.empty())
8657  {
8658  HVPairUnderExamination = HVLinkedList.front();
8659  HVLinkedList.pop_front();
8660  HVPairNew.first = HVPairUnderExamination.first;
8661  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8662  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8663  if(HVPLMIt != HVPairsLinkedMap.end())
8664  {
8665  if(!HVPLMIt->second)
8666  {
8667  HVLinkedList.push_back(HVPLMIt->first);
8668  }
8669  HVPLMIt->second = true;
8670  }
8671  HVPairNew.first = HVPairUnderExamination.first - 1;
8672  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8673  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8674  if(HVPLMIt != HVPairsLinkedMap.end())
8675  {
8676  if(!HVPLMIt->second)
8677  {
8678  HVLinkedList.push_back(HVPLMIt->first);
8679  }
8680  HVPLMIt->second = true;
8681  }
8682  HVPairNew.first = HVPairUnderExamination.first;
8683  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8684  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8685  if(HVPLMIt != HVPairsLinkedMap.end())
8686  {
8687  if(!HVPLMIt->second)
8688  {
8689  HVLinkedList.push_back(HVPLMIt->first);
8690  }
8691  HVPLMIt->second = true;
8692  }
8693  HVPairNew.first = HVPairUnderExamination.first + 1;
8694  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8695  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8696  if(HVPLMIt != HVPairsLinkedMap.end())
8697  {
8698  if(!HVPLMIt->second)
8699  {
8700  HVLinkedList.push_back(HVPLMIt->first);
8701  }
8702  HVPLMIt->second = true;
8703  }
8704  }
8705 
8706  //at the end if any have a false bool then the name is duplicated so return false
8707  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8708  {
8709  if(!HVPLMIt->second)
8710  {
8711  Utilities->CallLogPop(2258);
8712  return(false);
8713  }
8714  }
8715  Utilities->CallLogPop(2259);
8716  return(true);
8717 }
8718 
8719 // ---------------------------------------------------------------------------
8720 
8721 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8722 /*
8723  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8724 */
8725 
8726 {
8727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8728  if(LocationName == "")
8729  {
8730  Utilities->CallLogPop(577);
8731  return(false);
8732  }
8733 // new for v0.2b
8734 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8736  {
8737  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8738  ActiveTrackElementNameMap.clear();
8739  for(unsigned int x = 0; x < TrackVector.size(); x++)
8740  {
8741  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8742  == ContinuationNameMap.end())
8743  {
8744  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8745  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8746  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8747  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8748  }
8749  }
8751  }
8752  Utilities->CallLogPop(578);
8753  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8754 // end of new section
8755 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8756 }
8757 
8758 // ---------------------------------------------------------------------------
8759 
8760 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8761 /*
8762  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8763  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8764  new names in the vectors.
8765 */
8766 {
8767  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8768  bool FoundFlag, ErasedFlag = false;
8769  TLocationNameMultiMapIterator SNIterator;
8770  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8771 
8772  if(SNRange.first != SNRange.second)
8773  {
8774  ErasedFlag = true;
8775  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8776  {
8777  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8778  TVIt->LocationName = "";
8779  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8780  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8781  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8782  {
8783  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8784  if(FoundFlag)
8785  {
8786  TrackElementAt(25, Position).LocationName = "";
8787  TrackElementAt(26, Position).ActiveTrackElementName = "";
8788  }
8789  }
8790  }
8791  }
8792  if(ErasedFlag)
8793  {
8795  }
8796  CheckLocationNameMultiMap(3); // test
8797  Utilities->CallLogPop(579);
8798 }
8799 
8800 // ---------------------------------------------------------------------------
8801 
8802 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8803 /*
8804  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8805  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8806  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8807  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8808  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8809  naming up to date with the deletion or insertion.
8810 */
8811 {
8812  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8813  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8814  LNPendingList.clear();
8815  AnsiString LocationName;
8816  int MapPos;
8817  bool FoundFlag = 0;
8818 
8819 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8820  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8821  if(FoundFlag)
8822  {
8823  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8824  if(LocationName != "")
8825  {
8826  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8827  EnterLocationName(13, LocationName, true);
8828  Utilities->CallLogPop(2251);
8829  return;
8830  }
8831  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8832  if(LocationName != "")
8833  {
8834  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8835  EnterLocationName(14, LocationName, true);
8836  Utilities->CallLogPop(2252);
8837  return;
8838  }
8839  }
8840 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8841 
8842  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8843  if(FoundFlag)
8844  {
8845  LocationName = TrackElementAt(1004, Position).LocationName;
8846  if(LocationName != "")
8847  {
8848  int ModifiedPosition = -1 - Position;
8849  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8850  EnterLocationName(15, LocationName, true);
8851  Utilities->CallLogPop(2253);
8852  return;
8853  }
8854  }
8855  if(SpeedTag == 76) // top plat
8856  {
8857  for(int x = 0; x < 25; x++)
8858  {
8859  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8860  {
8861  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8862  EnterLocationName(3, LocationName, true);
8863  break;
8864  }
8865  }
8866  }
8867  else if(SpeedTag == 77) // bot plat
8868  {
8869  for(int x = 0; x < 25; x++)
8870  {
8871  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8872  {
8873  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8874  EnterLocationName(4, LocationName, true);
8875  break;
8876  }
8877  }
8878  }
8879  else if(SpeedTag == 78) // l plat
8880  {
8881  for(int x = 0; x < 25; x++)
8882  {
8883  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8884  {
8885  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8886  EnterLocationName(5, LocationName, true);
8887  break;
8888  }
8889  }
8890  }
8891  else if(SpeedTag == 79) // r plat
8892  {
8893  for(int x = 0; x < 25; x++)
8894  {
8895  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8896  {
8897  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8898  EnterLocationName(6, LocationName, true);
8899  break;
8900  }
8901  }
8902  }
8903  else if(SpeedTag == 96) // conc
8904  {
8905  for(int x = 0; x < 28; x++)
8906  {
8907  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8908  {
8909  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8910  EnterLocationName(7, LocationName, true);
8911  break;
8912  }
8913  }
8914  }
8915  else if(SpeedTag == 129) // vert footbridge
8916  {
8917  for(int x = 0; x < 8; x++)
8918  {
8919  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8920  {
8921  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8922  EnterLocationName(8, LocationName, true);
8923  break;
8924  }
8925  }
8926  }
8927  else if(SpeedTag == 130) // hor footbridge
8928  {
8929  for(int x = 0; x < 8; x++)
8930  {
8931  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8932  {
8933  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8934  EnterLocationName(9, LocationName, true);
8935  break;
8936  }
8937  }
8938  }
8939  else if(SpeedTag == 145) // vert u'pass
8940  {
8941  for(int x = 0; x < 8; x++)
8942  {
8943  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8944  {
8945  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8946  EnterLocationName(11, LocationName, true);
8947  break;
8948  }
8949  }
8950  }
8951  else if(SpeedTag == 146) // hor u'pass
8952  {
8953  for(int x = 0; x < 8; x++)
8954  {
8955  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8956  {
8957  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8958  EnterLocationName(12, LocationName, true);
8959  break;
8960  }
8961  }
8962  }
8963  else if(SpeedTag == 131) // named location
8964  {
8965  for(int x = 0; x < 4; x++)
8966  {
8967  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8968  {
8969  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8970  EnterLocationName(10, LocationName, true);
8971  break;
8972  }
8973  }
8974  }
8975 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8976  Utilities->CallLogPop(580);
8977 }
8978 
8979 // ---------------------------------------------------------------------------
8980 
8981 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8982 /*
8983  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8984  true if a LocationName is found, and also returns the name and the adjusted vector position.
8985 */
8986 {
8987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8988  AnsiString(SpeedTag));
8989  bool FoundFlag;
8990  TIMPair IMPair;
8991  TTrackVectorIterator TempElement;
8992  int Position;
8993 
8994  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8995  if(FoundFlag)
8996  {
8997  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8998  {
8999  TempElement = InactiveTrackVector.begin() + IMPair.first;
9000  if(TempElement->LocationName != "")
9001  {
9002  LocationName = TempElement->LocationName;
9003  FoundElement = IMPair.first;
9004  Utilities->CallLogPop(581);
9005  return(true);
9006  }
9007  }
9008  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9009  {
9010  TempElement = InactiveTrackVector.begin() + IMPair.second;
9011  if(TempElement->LocationName != "")
9012  {
9013  LocationName = TempElement->LocationName;
9014  FoundElement = IMPair.second;
9015  Utilities->CallLogPop(582);
9016  return(true);
9017  }
9018  }
9019  }
9020  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9021  if(FoundFlag)
9022  {
9023  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9024  {
9025  TempElement = TrackVector.begin() + Position;
9026  if(TempElement->LocationName != "")
9027  {
9028  LocationName = TempElement->LocationName;
9029  FoundElement = -1 - Position;
9030  Utilities->CallLogPop(583);
9031  return(true);
9032  }
9033  }
9034  }
9035  Utilities->CallLogPop(584);
9036  return(false);
9037 }
9038 
9039 // ---------------------------------------------------------------------------
9040 
9041 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9042 {
9043 // check quantity in map & vectors match
9044  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9045  unsigned int Count = 0;
9046 
9047  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9048  {
9049  Utilities->CallLogPop(2059);
9050  return;
9051  }
9052  AnsiString SName, TName, ErrorString;
9053 
9054  for(unsigned int x = 0; x < TrackVector.size(); x++)
9055  {
9056  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9057  {
9058  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9059  {
9060  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9061  AnsiString(Caller));
9062  }
9063  Count++;
9064  }
9065  }
9066  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9067  {
9068  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9069  {
9070  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9071  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9072  {
9073  throw Exception
9074  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9075  AnsiString(Caller));
9076  }
9077  Count++;
9078  }
9079  }
9080  if(LocationNameMultiMap.size() != Count)
9081  {
9082  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9083  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9084  }
9085 // check all entries in both vectors match entries in name multimap
9087 
9088  for(unsigned int x = 0; x < TrackVector.size(); x++)
9089  {
9090  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9091  {
9092  SName = TrackElementAt(1365, x).LocationName;
9093  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9094  if(ErrorString != "")
9095  {
9096  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9097  }
9098  if(SNIt->second != -1 - (int)x)
9099  {
9100  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9101  AnsiString(Caller));
9102  }
9103  }
9104  // check corresponding platform for all Timetable entries that aren't empty
9105  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9106  TIMPair IMPair;
9107  bool FoundFlag = false;
9108  if(TName != "")
9109  {
9110  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9111  if(FoundFlag)
9112  {
9113  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9115  {
9116  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9117  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9118  }
9119  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9120  {
9121  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9122  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9123  AnsiString(Caller));
9124  }
9125  }
9126  else
9127  {
9128  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9129  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9130  }
9131  }
9132  }
9133  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9134  {
9135  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9136  {
9137  SName = InactiveTrackElementAt(148, x).LocationName;
9138  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9139  if(ErrorString != "")
9140  {
9141  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9142  }
9143  if(SNIt->second != (int)x)
9144  {
9145  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9146  AnsiString(Caller));
9147  }
9148  }
9149  }
9150  Utilities->CallLogPop(585);
9151 }
9152 
9153 // ---------------------------------------------------------------------------
9154 
9156  AnsiString &ErrorString)
9157 {
9158 /*
9159  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9160  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9161  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9162 */
9163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9164  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9165  ErrorString = "";
9166  bool FoundFlag = false;
9167  TLocationNameMultiMapIterator SNIterator;
9168  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9169 
9170  if(SNRange.first == SNRange.second)
9171  {
9172  ErrorString = "Error, Name " + LocationName + " not found in map";
9173  Utilities->CallLogPop(586);
9174  return(SNRange.first);
9175  }
9176  else
9177  {
9178  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9179  {
9180  if(SNIterator->second < 0)
9181  {
9182  int TVPos = -1 - SNIterator->second;
9183  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9184  if(TVIt == TrackElement)
9185  {
9186  FoundFlag = true;
9187  Utilities->CallLogPop(587);
9188  return(SNIterator);
9189  }
9190  }
9191  else
9192  {
9193  int ITVPos = SNIterator->second;
9194  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9195  if(ITVIt == TrackElement)
9196  {
9197  FoundFlag = true;
9198  Utilities->CallLogPop(588);
9199  return(SNIterator);
9200  }
9201  }
9202  }
9203  }
9204  if(!FoundFlag)
9205  {
9206  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9207  }
9208  Utilities->CallLogPop(589);
9209  return(SNIterator);
9210 }
9211 
9212 // ---------------------------------------------------------------------------
9213 
9214 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9215 {
9216 /*
9217  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9218  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9219 */
9220  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9221  TLocationNameMultiMapEntry LocationNameEntry;
9222 
9223  LocationNameEntry.first = NewName;
9224  LocationNameEntry.second = SNIterator->second;
9225  LocationNameMultiMap.erase(SNIterator);
9226  LocationNameMultiMap.insert(LocationNameEntry);
9227  Utilities->CallLogPop(590);
9228 }
9229 
9230 // ---------------------------------------------------------------------------
9231 
9233 {
9234 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9235  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9236  if(Position < 0) // footcrossing
9237  {
9238  int TruePos = -1 - Position;
9239  // new check at v0.2b
9240  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9241  {
9242  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9243  }
9244  Utilities->CallLogPop(591);
9245  return (TrackVector.begin() + TruePos);
9246  }
9247  else
9248  {
9249  // new check at v0.2b
9250  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9251  {
9252  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9253  }
9254  Utilities->CallLogPop(592);
9255  return (InactiveTrackVector.begin() + Position);
9256  }
9257 }
9258 
9259 // ---------------------------------------------------------------------------
9260 
9261 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9262 {
9263 /*
9264  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9265  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9266  LocationNameMultiMap.
9267 */
9268  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9269  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9270  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9271 
9272  if(!InactiveTrack2MultiMap.empty())
9273  {
9274  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9275  InactiveTrack2MultiMapIterator++)
9276  {
9277  if(InactiveTrack2MultiMapIterator->second > VecPos)
9278  {
9279  InactiveTrack2MultiMapIterator->second--;
9280  }
9281  // can't be == VecPos as that position erased
9282  }
9283  }
9284  if(!LocationNameMultiMap.empty())
9285  {
9286  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9287  LocationNameMultiMapIterator++)
9288  {
9289  if(LocationNameMultiMapIterator->second < 0)
9290  {
9291  continue; // deal with TrackVectors separately
9292  }
9293  if(LocationNameMultiMapIterator->second > (int)VecPos)
9294  {
9295  LocationNameMultiMapIterator->second--;
9296  }
9297  }
9298  }
9299  Utilities->CallLogPop(593);
9300 }
9301 
9302 // ---------------------------------------------------------------------------
9303 
9304 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9305 {
9306 /*
9307  After an element has been erased from the track vector, all the later elements are moved down one. This function
9308  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9309  LocationNameMultiMap.
9310 */
9311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9312  TTrackMapIterator TrackMapIterator;
9313  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9314 
9315  if(!TrackMap.empty())
9316  {
9317  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9318  {
9319  if(TrackMapIterator->second > VecPos)
9320  {
9321  TrackMapIterator->second--;
9322  }
9323  // can't be == VecPos as that position erased
9324  }
9325  }
9326  if(!LocationNameMultiMap.empty())
9327  {
9328  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9329  LocationNameMultiMapIterator++)
9330  {
9331  if(LocationNameMultiMapIterator->second >= 0)
9332  {
9333  continue; // deal with InactiveTrackVectors separately
9334  }
9335  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9336  // Val -1 -2 -3 -4 -5 -6 -7 -8
9337  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9338  {
9339  LocationNameMultiMapIterator->second++;
9340  }
9341  }
9342  }
9343  for(unsigned int x = 0; x < TrackVector.size(); x++)
9344  {
9345  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9346  if(TkEl.TrackType == GapJump)
9347  {
9348  // position 0 is the gap
9349  if(TkEl.Conn[0] == int(VecPos))
9350  {
9351  TkEl.Conn[0] = -1; // connected to a deleted gap
9352  continue;
9353  }
9354  if(TkEl.Conn[0] > int(VecPos))
9355  {
9356  TkEl.Conn[0]--;
9357  }
9358  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9359  {
9360  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9361  {
9362  TkEl.Conn[0] = -1;
9363  }
9364  }
9365  }
9366  }
9367  Utilities->CallLogPop(1433);
9368 }
9369 
9370 // ---------------------------------------------------------------------------
9371 
9373 /*
9374  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9375  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9376  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9377 */
9378 {
9379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9380  LocationNameMultiMap.clear();
9381  TLocationNameMultiMapEntry LocationNameEntry;
9382  TTrackElement TrackElement;
9383 
9384  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9385  {
9386  TrackElement = TrackElementAt(1376, TVPos);
9387  if(TrackElement.FixedNamedLocationElement)
9388  {
9389  LocationNameEntry.first = TrackElement.LocationName;
9390  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9391  LocationNameMultiMap.insert(LocationNameEntry);
9392  }
9393  }
9394 
9395  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9396  {
9397  TrackElement = InactiveTrackElementAt(149, ITVPos);
9398  if(TrackElement.FixedNamedLocationElement)
9399  {
9400  LocationNameEntry.first = TrackElement.LocationName;
9401  LocationNameEntry.second = ITVPos;
9402  LocationNameMultiMap.insert(LocationNameEntry);
9403  }
9404  }
9405  Utilities->CallLogPop(594);
9406 }
9407 
9408 // ---------------------------------------------------------------------------
9409 
9411 // Return true if there is a named location present in the railway
9412 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9413 {
9414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9415  TTrackVectorIterator ITVI;
9416 
9417  if(InactiveTrackVector.empty())
9418  {
9419  Utilities->CallLogPop(1343);
9420  return(false);
9421  }
9422  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9423  {
9424  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9425  {
9426  Utilities->CallLogPop(1404);
9427  return(true);
9428  }
9429  }
9430  Utilities->CallLogPop(1344);
9431  return(false);
9432 }
9433 
9434 // ---------------------------------------------------------------------------
9435 
9437 /*
9438  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9439 */
9440 {
9441  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9442 // ResetDistanceElements(6);
9443  for(unsigned int x = 0; x < TrackVector.size(); x++)
9444  {
9445  TTrackElement &TE = TrackElementAt(718, x);
9448  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9449  {
9452  }
9453  }
9454 /* old function
9455  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9456  {
9457  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9458  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9459  }
9460  else
9461  {
9462  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9463  }
9464  }
9465 */
9466  Utilities->CallLogPop(617);
9467 }
9468 
9469 // ---------------------------------------------------------------------------
9470 
9471 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9472 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9473 {
9474  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9475  for(unsigned int x = 0; x < TrackVector.size(); x++)
9476  {
9477  TTrackElement TempElement = TrackElementAt(1377, x);
9478  if(TempElement.Length01 > -1)
9479  {
9480  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9481  }
9482  if(TempElement.Length23 > -1)
9483  {
9484  MarkOneLength(2, TempElement, false, Disp);
9485  }
9486  }
9487  Disp->Update();
9488  Utilities->CallLogPop(618);
9489 }
9490 
9491 // ---------------------------------------------------------------------------
9492 
9493 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9494 /*
9495  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9496  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9497  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9498  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9499  track as indicated by FirstTrack (true for track01 & false for track23).
9500 */
9501 {
9502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9503  AnsiString((short)FirstTrack));
9504  bool LengthDifferent = false, SpeedDifferent = false;
9505 
9506  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9507  {
9508  Utilities->CallLogPop(619);
9509  return;
9510  }
9511  int EXArray[16][2] =
9512  {{4, 6}, {2, 8}, // horizontal & vertical
9513  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9514  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9515  {1, 9}, {3, 7}}; // forward & reverse diagonals
9516 
9517  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9518  Graphics::TBitmap *Bitmap;
9519 
9520  if(FirstTrack)
9521  {
9522  InLink = TrackElement.Link[0];
9523  OutLink = TrackElement.Link[1];
9524  }
9525  else
9526  {
9527  InLink = TrackElement.Link[2];
9528  OutLink = TrackElement.Link[3];
9529  }
9530  for(int x = 0; x < 16; x++)
9531  {
9532  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9533  {
9534  Index = x;
9535  }
9536  }
9537  if(Index == -1)
9538  {
9539  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9540  }
9541 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9542  the graphic for each of which is different because of the shape of the overbridge. The basic
9543  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9544  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9545  int BrEXArray[24][2] = {
9546  {4,6},{2,8},{1,9},{3,7},
9547  {1,9},{3,7},{1,9},{3,7},
9548  {2,8},{4,6},{2,8},{4,6}
9549 */
9550  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9551  {
9552  if(Index == 1)
9553  {
9554  if(TrackElement.SpeedTag == 49)
9555  {
9556  BrNum = 1 + 16;
9557  }
9558  else if(TrackElement.SpeedTag == 54)
9559  {
9560  BrNum = 8 + 16;
9561  }
9562  else if(TrackElement.SpeedTag == 55)
9563  {
9564  BrNum = 10 + 16;
9565  }
9566  }
9567  else if(Index == 0)
9568  {
9569  if(TrackElement.SpeedTag == 48)
9570  {
9571  BrNum = 0 + 16;
9572  }
9573  else if(TrackElement.SpeedTag == 58)
9574  {
9575  BrNum = 11 + 16;
9576  }
9577  else if(TrackElement.SpeedTag == 59)
9578  {
9579  BrNum = 9 + 16;
9580  }
9581  }
9582  else if(Index == 14)
9583  {
9584  if(TrackElement.SpeedTag == 50)
9585  {
9586  BrNum = 2 + 16;
9587  }
9588  else if(TrackElement.SpeedTag == 52)
9589  {
9590  BrNum = 4 + 16;
9591  }
9592  else if(TrackElement.SpeedTag == 57)
9593  {
9594  BrNum = 6 + 16;
9595  }
9596  }
9597  else if(Index == 15)
9598  {
9599  if(TrackElement.SpeedTag == 51)
9600  {
9601  BrNum = 3 + 16;
9602  }
9603  else if(TrackElement.SpeedTag == 53)
9604  {
9605  BrNum = 7 + 16;
9606  }
9607  else if(TrackElement.SpeedTag == 56)
9608  {
9609  BrNum = 5 + 16;
9610  }
9611  }
9612  }
9613  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9614  {
9615  GrNum = BrNum;
9616  }
9617  else
9618  {
9619  GrNum = Index;
9620  }
9621  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9622  {
9623  if(GrNum > 15) // underbridge
9624  {
9625  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9626  }
9627  else
9628  {
9629  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9630  }
9631  if(TrackElement.SpeedTag == 64)
9632  {
9633  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9634  }
9635  if(TrackElement.SpeedTag == 65)
9636  {
9638  }
9639  if(TrackElement.SpeedTag == 66)
9640  {
9642  }
9643  if(TrackElement.SpeedTag == 67)
9644  {
9646  }
9647  if(TrackElement.SpeedTag == 80)
9648  {
9649  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9650  }
9651  if(TrackElement.SpeedTag == 81)
9652  {
9654  }
9655  if(TrackElement.SpeedTag == 82)
9656  {
9658  }
9659  if(TrackElement.SpeedTag == 83)
9660  {
9662  }
9663  if(TrackElement.SpeedTag == 84)
9664  {
9666  }
9667  if(TrackElement.SpeedTag == 85)
9668  {
9670  }
9671  if(TrackElement.SpeedTag == 86)
9672  {
9674  }
9675  if(TrackElement.SpeedTag == 87)
9676  {
9678  }
9679  if(TrackElement.SpeedTag == 129)
9680  {
9681  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9682  }
9683  if(TrackElement.SpeedTag == 130)
9684  {
9686  }
9687  }
9688 
9689  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9690  {
9691  if(GrNum > 15) // underbridge
9692  {
9693  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9694  }
9695  else
9696  {
9697  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9698  }
9699  if(TrackElement.SpeedTag == 64)
9700  {
9701  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9702  }
9703  if(TrackElement.SpeedTag == 65)
9704  {
9705  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9706  }
9707  if(TrackElement.SpeedTag == 66)
9708  {
9709  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9710  }
9711  if(TrackElement.SpeedTag == 67)
9712  {
9713  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9714  }
9715  if(TrackElement.SpeedTag == 80)
9716  {
9717  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9718  }
9719  if(TrackElement.SpeedTag == 81)
9720  {
9721  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9722  }
9723  if(TrackElement.SpeedTag == 82)
9724  {
9725  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9726  }
9727  if(TrackElement.SpeedTag == 83)
9728  {
9729  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9730  }
9731  if(TrackElement.SpeedTag == 84)
9732  {
9733  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9734  }
9735  if(TrackElement.SpeedTag == 85)
9736  {
9737  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9738  }
9739  if(TrackElement.SpeedTag == 86)
9740  {
9741  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9742  }
9743  if(TrackElement.SpeedTag == 87)
9744  {
9745  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9746  }
9747  if(TrackElement.SpeedTag == 129)
9748  {
9749  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9750  }
9751  if(TrackElement.SpeedTag == 130)
9752  {
9753  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9754  }
9755  }
9756 
9757  else // SpeedDifferent only: red - use non sig graphics
9758  {
9759  if(GrNum > 15) // underbridge
9760  {
9761  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9762  }
9763  else
9764  {
9765  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9766  }
9767  if(TrackElement.SpeedTag == 64)
9768  {
9769  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9770  }
9771  if(TrackElement.SpeedTag == 65)
9772  {
9774  }
9775  if(TrackElement.SpeedTag == 66)
9776  {
9778  }
9779  if(TrackElement.SpeedTag == 67)
9780  {
9782  }
9783  if(TrackElement.SpeedTag == 80)
9784  {
9785  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9786  }
9787  if(TrackElement.SpeedTag == 81)
9788  {
9790  }
9791  if(TrackElement.SpeedTag == 82)
9792  {
9794  }
9795  if(TrackElement.SpeedTag == 83)
9796  {
9798  }
9799  if(TrackElement.SpeedTag == 84)
9800  {
9802  }
9803  if(TrackElement.SpeedTag == 85)
9804  {
9806  }
9807  if(TrackElement.SpeedTag == 86)
9808  {
9810  }
9811  if(TrackElement.SpeedTag == 87)
9812  {
9814  }
9815  if(TrackElement.SpeedTag == 129)
9816  {
9817  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9818  }
9819  if(TrackElement.SpeedTag == 130)
9820  {
9822  }
9823  }
9824  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9825  Utilities->CallLogPop(620);
9826 }
9827 
9828 // ---------------------------------------------------------------------------
9829 
9830 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9831 /* FirstTrack = LinkPos's 0 & 1
9832  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9833 */
9834 {
9835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9836  AnsiString((short)FirstTrack));
9837  LengthDifferent = false;
9838  SpeedDifferent = false;
9839  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9840  {
9841  if(TrackElement.Length01 != DefaultTrackLength)
9842  {
9843  LengthDifferent = true;
9844  }
9845  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9846  {
9847  SpeedDifferent = true;
9848  }
9849  if(LengthDifferent || SpeedDifferent)
9850  {
9851  Utilities->CallLogPop(625);
9852  return(false);
9853  }
9854  Utilities->CallLogPop(626);
9855  return(true);
9856  }
9857 
9858  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9859  {
9860  if(TrackElement.Length23 != DefaultTrackLength)
9861  {
9862  LengthDifferent = true;
9863  }
9864  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9865  {
9866  SpeedDifferent = true;
9867  }
9868  if(LengthDifferent || SpeedDifferent)
9869  {
9870  Utilities->CallLogPop(627);
9871  return(false);
9872  }
9873  Utilities->CallLogPop(628);
9874  return(true);
9875  }
9876 
9877  else // any other 1 track element, including platforms being present
9878  {
9879  if(TrackElement.Length01 != DefaultTrackLength)
9880  {
9881  LengthDifferent = true;
9882  }
9883  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9884  {
9885  SpeedDifferent = true;
9886  }
9887  if(LengthDifferent || SpeedDifferent)
9888  {
9889  Utilities->CallLogPop(629);
9890  return(false);
9891  }
9892  Utilities->CallLogPop(630);
9893  return(true);
9894  }
9895 }
9896 
9897 // ---------------------------------------------------------------------------
9898 
9899 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9900 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9901 {
9902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9903  AnsiString(VLoc));
9904  bool FoundFlag;
9905  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9906 
9907  if(!FoundFlag)
9908  {
9909  Utilities->CallLogPop(633);
9910  return(false);
9911  }
9912  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9913  {
9914  Utilities->CallLogPop(634);
9915  return(true); // only need to check first since if second is a platform the the first must be too
9916  }
9917  else
9918  {
9919  Utilities->CallLogPop(635);
9920  return(false);
9921  }
9922 }
9923 
9924 // ---------------------------------------------------------------------------
9925 
9926 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9927 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9928 {
9929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9930  AnsiString(VLoc));
9931  bool FoundFlag;
9932  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9933 
9934  if(!FoundFlag)
9935  {
9936  Utilities->CallLogPop(636);
9937  return(false);
9938  }
9940  {
9941  Utilities->CallLogPop(637);
9942  return(true); // only need to check first since only one used for NamedNonStationLocations
9943  }
9944  else
9945  {
9946  Utilities->CallLogPop(638);
9947  return(false);
9948  }
9949 }
9950 
9951 // ---------------------------------------------------------------------------
9952 
9954 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9955  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9956  the front of train stop points for each direction.
9957  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9958  end (unless buffers at one or both ends in which case stop points are the end elements).
9959  Note that for a single element the stop point is the element itself (formula doesn't apply).
9960  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9961  repeating the procedure for every element. At the end all unused values are returned to -1.
9962  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9963 */
9964 {
9965  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9966  TTrackElement TempElement, StartElement;
9967  AnsiString TempName;
9968  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9969  bool ForwardSet, ReverseSet;
9970 
9971  for(unsigned int x = 0; x < TrackVector.size(); x++)
9972  {
9975  }
9976  for(unsigned int x = 0; x < TrackVector.size(); x++)
9977  {
9978  ForwardSet = false;
9979  ReverseSet = false;
9980  TempElement = TrackElementAt(1380, x);
9981  VecPos = x;
9982  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9983  // 2nd condition incl so don't re-examine elements with stop links set to 5
9984  {
9985  TempName = TempElement.ActiveTrackElementName;
9986  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9987  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9988  // an element linked at both ends where both links are also named elements
9989  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9990  {
9991  continue; // looking for an end element so skip this one
9992  }
9993  else // reached one end
9994  {
9995  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9996  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9997  // single named element linked at both ends
9998  {
9999  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10000  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10001  continue;
10002  }
10003  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10004  // single named buffer element (LinkPos 1 is the non-buffer end)
10005  {
10006  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10007  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10008  continue;
10009  }
10010  else
10011  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10012  // and platforms always on straight (conns 0 & 1) section of points
10013  {
10014  for(int y = 0; y < 2; y++)
10015  {
10016  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10017  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10018 /* TTrackElement Temp1 = TempElement;
10019  ***********New section, compiles but not checked - does bit below need to be else if?
10020  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10021  {
10022  //search along Dir direction until find other end, skip if Dir facing buffer end
10023  int NewDir = Dir;
10024  int NewVecPos;
10025  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10026  {
10027  NewVecPos = Temp1.Conn[NewDir];
10028  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10029  Temp1 = TrackElementAt(601, NewVecPos);
10030  }
10031  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10032  {
10033  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10034  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10035  }
10036  }
10037  ***************
10038 */
10039  // end may be linked at both ends but only one link named, or buffer with linked element named
10040  // if a buffer then the named linkpos has to be 1
10041  // already dealt with all types of single element so at least 2 linked named element
10042  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10043  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10044  {
10045  StartElement = TempElement;
10046  StartVecPos = VecPos;
10047  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10048  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10049  EntryPos = 1 - Dir;
10050  StartEntryPos = 1 - Dir;
10051  Count = 1;
10052  // work along named elements until find the other end
10053  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10054  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10055  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10056  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10057  // all stop link pos's are set to 5
10058  {
10059  VecPos = TempElement.Conn[1 - EntryPos];
10060  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10061  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10062  EntryPos = TempEntryPos;
10063  Count++;
10064  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10065  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10066  }
10067  // here when reached other end, maybe buffers, continuation or last named linked element
10068  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10069  // terminal station, set end elements as stop elements
10070  {
10071  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10072  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10073  continue;
10074  }
10075  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10076  // terminal station, set end elements as stop elements
10077  {
10078  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10079  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10080  continue;
10081  }
10082  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10083  // NonStationLocation so set end elements as stop elements
10084  {
10085  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10086  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10087  continue;
10088  }
10089  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10090  ForwardNumber = ((Count + 1) / 2) + 1;
10091  ReverseNumber = (Count - ForwardNumber) + 1;
10092  Count = 1; // starting value
10093  EntryPos = 1 - Dir;
10094  TempElement = StartElement;
10095  VecPos = StartVecPos;
10096  if(Count == ForwardNumber)
10097  {
10098  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10099  ForwardSet = true;
10100  }
10101  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10102  {
10103  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10104  ReverseSet = true;
10105  }
10106  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10107  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10108  {
10109  VecPos = TempElement.Conn[1 - EntryPos];
10110  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10111  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10112  EntryPos = TempEntryPos;
10113  Count++;
10114  if(Count == ForwardNumber)
10115  {
10116  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10117  ForwardSet = true;
10118  }
10119  if(Count == ReverseNumber)
10120  {
10121  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10122  ReverseSet = true;
10123  }
10124  }
10125  }
10126  }
10127  }
10128  }
10129  }
10130  }
10131  for(unsigned int x = 0; x < TrackVector.size(); x++)
10132  {
10133  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10134  {
10136  }
10137  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10138  {
10140  }
10141  }
10142  Utilities->CallLogPop(639);
10143 }
10144 
10145 // ---------------------------------------------------------------------------
10146 
10147 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10148 {
10149  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10150  TTrackElement Next;
10151 
10153  while(ReturnNextInactiveTrackElement(1, Next))
10154  {
10155  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10156  {
10157  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10158  // need striped graphics
10159  {
10160  if(Next.SpeedTag == 76)
10161  {
10162  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10163  }
10164  else if(Next.SpeedTag == 77)
10165  {
10166  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10167  }
10168  else if(Next.SpeedTag == 78)
10169  {
10170  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10171  }
10172  else if(Next.SpeedTag == 79)
10173  {
10174  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10175  }
10176  else if(Next.SpeedTag == 96)
10177  {
10178  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10179  }
10180  else if(Next.SpeedTag == 131)
10181  {
10182  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10183  }
10184  }
10185  else
10186  {
10187  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10188  }
10189  }
10190  }
10191 
10192  NextTrackElementPtr = TrackVector.begin();
10193  while(ReturnNextTrackElement(1, Next))
10194  {
10195  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10196  {
10197  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10198  {
10199  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10200  {
10201  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10202  }
10203  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10204  {
10205  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10206  }
10207  }
10208  else
10209  {
10210  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10211  }
10212  }
10213  }
10214  Disp->Update();
10215  Utilities->CallLogPop(640);
10216 }
10217 
10218 // ---------------------------------------------------------------------------
10219 
10220 void TTrack::PlotSmallRedGap(int Caller)
10221 {
10222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10224  Utilities->CallLogPop(1346);
10225 }
10226 
10227 // ---------------------------------------------------------------------------
10228 
10229 void TTrack::TrackClear(int Caller)
10230 {
10231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10232  TrackVector.clear();
10233  InactiveTrackVector.clear();
10234  TrackMap.clear();
10236  if(TextHandler->TextVector.size() == 0)
10237  {
10238  Display->DisplayOffsetH = 0;
10239  Display->DisplayOffsetV = 0;
10246  HLocMin = 2000000000;
10247  HLocMax = -2000000000;
10248  VLocMin = 2000000000;
10249  VLocMax = -2000000000;
10250  }
10251  else
10252  {
10253  CalcHLocMinEtc(4);
10254  }
10255  Utilities->CallLogPop(1347);
10256 }
10257 
10258 // ---------------------------------------------------------------------------
10259 
10260 void TTrack::CalcHLocMinEtc(int Caller)
10261 {
10262  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10263  HLocMin = 2000000000;
10264  VLocMin = 2000000000;
10265  HLocMax = -2000000000;
10266  VLocMax = -2000000000;
10267  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10268  {
10269  if(TrackElementAt(1385, x).SpeedTag == 0)
10270  {
10271  continue; // skip erase elements or would interfere with Min & Max values
10272  }
10273  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10274  {
10275  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10276  }
10277  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10278  {
10279  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10280  }
10281  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10282  {
10283  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10284  }
10285  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10286  {
10287  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10288  }
10289  }
10290  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10291  {
10292  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10293  {
10294  continue; // shouldn't be any inactive erase elements but include anyway
10295  }
10296  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10297  {
10298  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10299  }
10300  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10301  {
10302  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10303  }
10304  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10305  {
10306  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10307  }
10308  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10309  {
10310  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10311  }
10312  }
10313  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10314  {
10315 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10316  will fail as x will exceed the maximum value
10317  if(TextHandler->TextPtrAt(, x)->TextString == "")
10318  {
10319  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10320  }
10321 */
10322  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10323  if((TextH / 16) - 1 < HLocMin)
10324  {
10325  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10326  }
10327  if((TextH / 16) + 1 > HLocMax)
10328  {
10329  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10330  }
10331  if((TextV / 16) - 1 < VLocMin)
10332  {
10333  VLocMin = (TextV / 16) - 1;
10334  }
10335  if((TextV / 16) + 1 > VLocMax)
10336  {
10337  VLocMax = (TextV / 16) + 1;
10338  }
10339  }
10340  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10341  {
10342  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10343  {
10344  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10345  }
10346  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10347  {
10348  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10349  }
10350  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10351  {
10352  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10353  }
10354  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10355  {
10356  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10357  }
10358  }
10359 
10360  Utilities->CallLogPop(641);
10361 }
10362 
10363 // ---------------------------------------------------------------------------
10364 
10365 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10366  bool &UserGraphicFoundFlag)
10367 {
10368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10369  TUserGraphicVector::iterator UserGraphicPtr;
10370 
10371  UserGraphicFoundFlag = false;
10372  if(!UserGraphicVector.empty())
10373  {
10374  int x = UserGraphicVector.size();
10375  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10376  {
10377  x--;
10378  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10379  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10380  {
10381  UserGraphicItem = x;
10382  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10383  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10384  UserGraphicFoundFlag = true;
10385  Utilities->CallLogPop(2177);
10386  return;
10387  } // if ....
10388 
10389  } // for UserGraphicPtr...
10390  } // if !UserGraphicVector...
10391 
10392  Utilities->CallLogPop(2197);
10393 }
10394 
10395 // ---------------------------------------------------------------------------
10396 
10398 {
10399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10400  TrackElement.LogTrack(11));
10401  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10402  int SpeedTag = TrackElement.SpeedTag;
10403 
10404  if(SpeedTag < 1)
10405  {
10406  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10407  }
10408  switch(SpeedTag)
10409  {
10410  case 76: // t platform
10411  GraphicOutput = RailGraphics->gl76Striped;
10412  break;
10413 
10414  case 77: // h platform
10415  GraphicOutput = RailGraphics->bm77Striped;
10416  break;
10417 
10418  case 78: // v platform
10419  GraphicOutput = RailGraphics->bm78Striped;
10420  break;
10421 
10422  case 79: // r platform
10423  GraphicOutput = RailGraphics->gl79Striped;
10424  break;
10425 
10426  case 96: // concourse
10427  GraphicOutput = RailGraphics->ConcourseStriped;
10428  break;
10429 
10430  case 129: // v footbridge
10431  GraphicOutput = RailGraphics->gl129Striped;
10432  break;
10433 
10434  case 130: // h footbridge
10435  GraphicOutput = RailGraphics->gl130Striped;
10436  break;
10437 
10438  case 131: // non-station named loc
10439  GraphicOutput = RailGraphics->bmNameStriped;
10440  break;
10441 
10442  case 145: // v u'pass
10443  GraphicOutput = RailGraphics->gl145Striped;
10444  break;
10445 
10446  case 146: // h u'pass
10447  GraphicOutput = RailGraphics->gl146Striped;
10448  break;
10449 
10450  default:
10451  GraphicOutput = TrackElement.GraphicPtr;
10452  break;
10453  }
10454  Utilities->CallLogPop(642);
10455  return(GraphicOutput);
10456 }
10457 
10458 // ---------------------------------------------------------------------------
10459 
10461 {
10462  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10463  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10464  {
10465 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10466  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10467  }
10468  Utilities->CallLogPop(643);
10469  return(TrackVector.at(At));
10470 }
10471 
10472 // ---------------------------------------------------------------------------
10473 
10475 {
10476  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10477  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10478  {
10479  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10480  " in InactiveTrackElementAt");
10481  }
10482  Utilities->CallLogPop(644);
10483  return(InactiveTrackVector.at(At));
10484 }
10485 
10486 // ---------------------------------------------------------------------------
10487 
10488 bool TTrack::BlankElementAt(int Caller, int At) const
10489 {
10490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10491  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10492  {
10493  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10494  }
10495  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10496  {
10497  Utilities->CallLogPop(645);
10498  return(true);
10499  }
10500  else
10501  {
10502  Utilities->CallLogPop(646);
10503  return(false);
10504  }
10505 }
10506 
10507 // ---------------------------------------------------------------------------
10508 
10509 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10510 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10511  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10512  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10513  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10514  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10515 */
10516 {
10517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10518  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10519  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10520  TLocationNameMultiMapIterator SNIterator;
10521  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10522 
10523  if(SNRange.first == SNRange.second)
10524  {
10525  Utilities->CallLogPop(972);
10526  return(false); // should have been caught earlier but include for completeness
10527  }
10528  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10529  {
10530  if(SNIterator->second < 0)
10531  {
10532  continue; // exclude footcrossings
10533  }
10534  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10535  if(InactiveElement.TrackType == Concourse)
10536  {
10537  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10538  }
10539  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10540  {
10541  continue; // only interested in locations where ActiveTrackElementName may be set
10542  }
10543  THVPair HVPair;
10544  HVPair.first = InactiveElement.HLoc;
10545  HVPair.second = InactiveElement.VLoc;
10546  if(TrackMap.find(HVPair) == TrackMap.end())
10547  {
10548  throw Exception
10549  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10550  }
10551  int TVPos = TrackMap.find(HVPair)->second;
10552  FirstNamedElement = TrackElementAt(560, TVPos);
10553  // first check linked on both sides, skip the check if not
10554  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10555  {
10556  continue;
10557  }
10558  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10559  // ActiveTrackElementNames are points and excluding trailing connections for points
10560  FirstNamedExitPos = 0;
10561  {
10562  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10563  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10564  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10565  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10566  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10567  {
10568  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10569  {
10570  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10571  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10572  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10573  // success, now check FirstNamedElement link not trailing points & if so all OK
10574  {
10575  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10576  {
10577  Utilities->CallLogPop(1002);
10578  return(true);
10579  }
10580  }
10581  }
10582  }
10583  }
10584  // failed, try link 1
10585  FirstNamedExitPos = 1;
10586  {
10587  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10588  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10589  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10590  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10591  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10592  {
10593  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10594  {
10595  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10596  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10597  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10598  // success, now check FirstNamedElement link not trailing points & if so all OK
10599  {
10600  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10601  {
10602  Utilities->CallLogPop(1003);
10603  return(true);
10604  }
10605  }
10606  }
10607  }
10608  }
10609  }
10610  Utilities->CallLogPop(1004);
10611  return(false);
10612 }
10613 
10614 // ---------------------------------------------------------------------------
10615 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10616  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10617 // for success need two linked named location elements, so that one element of each train can be at the location
10618 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10619 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10620 // the two trains will occupy these 4 elements
10621 // All are track vector positions, all but the input being references and set within the function.
10622 {
10623 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10624  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10625  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10626  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10627  splitting.
10628 */
10629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10630  AnsiString(FirstNamedElementPos));
10631  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10632  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10633 
10634  SecondNamedElementPos = -1;
10635  FirstNamedLinkedElementPos = -1;
10636  SecondNamedLinkedElementPos = -1;
10637  TLocationNameMultiMapIterator SNIterator;
10638  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10639 
10640  if(SNRange.first == SNRange.second) // i.e. location name not in map
10641  {
10642  Utilities->CallLogPop(1005);
10643  return(false); // should have been caught earlier but include for completeness
10644  }
10645  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10646  {
10647  if(SNIterator->second < 0)
10648  {
10649  continue; // exclude footcrossings
10650  }
10651  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10652  if(InactiveElement.TrackType == Concourse)
10653  {
10654  continue; // only interested in locations where ActiveTrackElementName may be set
10655  }
10656  THVPair HVPair;
10657  HVPair.first = InactiveElement.HLoc;
10658  HVPair.second = InactiveElement.VLoc;
10659  if(TrackMap.find(HVPair) == TrackMap.end())
10660  {
10661  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10662  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10663  // then it won't be found in TrackMap but it's still legitimate.
10664  {
10665  continue;
10666  }
10667  else // for anything else throw the error
10668  {
10669  throw Exception
10670  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10671  );
10672  }
10673  }
10674  int TVPos = TrackMap.find(HVPair)->second;
10675  if(TVPos != FirstNamedElementPos)
10676  {
10677  continue; // looking for an exact match
10678  }
10679  FirstNamedElement = TrackElementAt(567, TVPos);
10680  // first check linked on both sides, skip the check if not
10681  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10682  {
10683  continue;
10684  }
10685  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10686  // ActiveTrackElementNames are points and excluding trailing connections for points
10687  FirstNamedExitPos = 0;
10688  {
10689  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10690  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10691  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10692  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10693  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10694  {
10695  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10696  {
10697  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10698  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10699  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10700  // success, now check FirstNamedElement link not trailing points & if so all OK
10701  {
10702  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10703  {
10704  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10705  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10706  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10707  Utilities->CallLogPop(1006);
10708  return(true);
10709  }
10710  }
10711  }
10712  }
10713  }
10714  // failed, try link 1
10715  FirstNamedExitPos = 1;
10716  {
10717  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10718  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10719  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10720  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10721  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10722  {
10723  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10724  {
10725  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10726  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10727  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10728  // success, now check FirstNamedElement link not trailing points & if so all OK
10729  {
10730  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10731  {
10732  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10733  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10734  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10735  Utilities->CallLogPop(1007);
10736  return(true);
10737  }
10738  }
10739  }
10740  }
10741  }
10742  }
10743  Utilities->CallLogPop(1008);
10744  return(false);
10745 }
10746 
10747 // ---------------------------------------------------------------------------
10748 
10749 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10750 {
10751  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10752  TLocationNameMultiMapIterator SNIterator;
10753  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10754 
10755  if(SNRange.first != SNRange.second)
10756  {
10757  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10758  {
10759  if(SNIterator->second < 0)
10760  {
10761  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10762  }
10763  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10764  SNIterator->second).TrackType == NamedNonStationLocation))
10765  {
10766  Utilities->CallLogPop(1121);
10767  return(true);
10768  }
10769  }
10770  }
10771  Utilities->CallLogPop(848);
10772  return(false);
10773 }
10774 
10775 // ---------------------------------------------------------------------------
10776 
10777 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10778 {
10779 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10780  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10781  "," + AnsiString(SpeedTag));
10782  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10783  {
10784  Utilities->CallLogPop(949);
10785  return(false);
10786  }
10787  bool FoundFlag;
10788  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10789 
10790  if(!FoundFlag)
10791  {
10792  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10793  }
10794  TTrackElement IAElement;
10795 
10796  if(SpeedTag == 68) // top sig
10797  {
10798  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10799  {
10800  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10801  {
10802  IAElement = InactiveTrackElementAt(50, IMPair.first);
10803  }
10804  else
10805  {
10806  IAElement = InactiveTrackElementAt(51, IMPair.second);
10807  }
10808  if(IAElement.LocationName == "")
10809  {
10810 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10811  SignalPlatformGraphic = RailGraphics->gl76Striped;
10812  }
10813  else
10814  {
10815 // SignalPlatformGraphic = RailGraphics->Plat68;
10816  SignalPlatformGraphic = RailGraphics->gl76;
10817  }
10818  Utilities->CallLogPop(950);
10819  return(true);
10820  }
10821  }
10822  else if(SpeedTag == 69) // bot sig
10823  {
10824  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10825  {
10826  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10827  {
10828  IAElement = InactiveTrackElementAt(77, IMPair.first);
10829  }
10830  else
10831  {
10832  IAElement = InactiveTrackElementAt(78, IMPair.second);
10833  }
10834  if(IAElement.LocationName == "")
10835  {
10836 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10837  SignalPlatformGraphic = RailGraphics->bm77Striped;
10838  }
10839  else
10840  {
10841 // SignalPlatformGraphic = RailGraphics->Plat69;
10842  SignalPlatformGraphic = RailGraphics->bm77;
10843  }
10844  Utilities->CallLogPop(951);
10845  return(true);
10846  }
10847  }
10848  else if(SpeedTag == 70) // left sig
10849  {
10850  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10851  {
10852  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10853  {
10854  IAElement = InactiveTrackElementAt(55, IMPair.first);
10855  }
10856  else
10857  {
10858  IAElement = InactiveTrackElementAt(82, IMPair.second);
10859  }
10860  if(IAElement.LocationName == "")
10861  {
10862 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10863  SignalPlatformGraphic = RailGraphics->bm78Striped;
10864  }
10865  else
10866  {
10867 // SignalPlatformGraphic = RailGraphics->Plat70;
10868  SignalPlatformGraphic = RailGraphics->bm78;
10869  }
10870  Utilities->CallLogPop(952);
10871  return(true);
10872  }
10873  }
10874  else if(SpeedTag == 71) // right sig
10875  {
10876  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10877  {
10878  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10879  {
10880  IAElement = InactiveTrackElementAt(85, IMPair.first);
10881  }
10882  else
10883  {
10884  IAElement = InactiveTrackElementAt(86, IMPair.second);
10885  }
10886  if(IAElement.LocationName == "")
10887  {
10888 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10889  SignalPlatformGraphic = RailGraphics->gl79Striped;
10890  }
10891  else
10892  {
10893 // SignalPlatformGraphic = RailGraphics->Plat71;
10894  SignalPlatformGraphic = RailGraphics->gl79;
10895  }
10896  Utilities->CallLogPop(953);
10897  return(true);
10898  }
10899  }
10900  Utilities->CallLogPop(954);
10901  return(false);
10902 }
10903 
10904 // ---------------------------------------------------------------------------
10905 
10906 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10907 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10908 // false if not, if NextPos == -1, or if only own train on the track
10909 {
10910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10911  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10912  if(NextEntryPos < 0)
10913  {
10914  Utilities->CallLogPop(1348);
10915  return(false);
10916  }
10917  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10918 
10919  if(TrackElement.TrackType != Bridge)
10920  {
10921  Utilities->CallLogPop(1349);
10922  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10923  }
10924 // bridge if reach here
10925  if(NextEntryPos > 1)
10926  {
10927  Utilities->CallLogPop(1350);
10928  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10929  }
10930  else
10931  {
10932  Utilities->CallLogPop(1351);
10933  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10934  }
10935 }
10936 
10937 // ---------------------------------------------------------------------------
10938 
10940 {
10941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
10942  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
10943  {
10944  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
10945  }
10946  Utilities->CallLogPop(1483);
10947  return(SelectVector.at(At));
10948 }
10949 
10950 // ---------------------------------------------------------------------------
10951 
10952 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
10953 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
10954 {
10955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
10956  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
10957  bool FoundFlag = false;
10958  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
10959  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
10960 
10961  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
10962  Utilities->CallLogPop(1538);
10963  return(FoundFlag);
10964 }
10965 
10966 // ---------------------------------------------------------------------------
10967 
10968 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
10969 {
10970 // return true if find an inactive element called 'Name'
10971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
10972  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
10973  bool FoundFlag = false;
10974 
10975  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10976  {
10977  if(InactiveTrackElementAt(158, x).LocationName == Name)
10978  {
10979  FoundFlag = true;
10980  int V = InactiveTrackElementAt(159, x).VLoc;
10981  int H = InactiveTrackElementAt(160, x).HLoc;
10982  if(V > VLocHi)
10983  {
10984  VLocHi = V;
10985  }
10986  if(V < VLocLo)
10987  {
10988  VLocLo = V;
10989  }
10990  if(H < HLoc)
10991  {
10992  HLoc = H;
10993  }
10994  }
10995  }
10996  if(FoundFlag)
10997  {
10998  VPosHi = 16 * VLocHi;
10999  VPosLo = 16 * VLocLo;
11000  HPos = 16 * HLoc;
11001  Utilities->CallLogPop(1562);
11002  return(true);
11003  }
11004  else
11005  {
11006  Utilities->CallLogPop(1563);
11007  return(false);
11008  }
11009 }
11010 
11011 // ---------------------------------------------------------------------------
11012 
11013 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11014 {
11015 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11016 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11018  AnsiString(EndTVPosition));
11019  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11020  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11021 
11022 // get H & V values for the element adjacent to Link[0] & Link[1]
11023  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11024  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11025  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11026  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11027 
11028 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11029  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11030  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11031  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11032  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11033 
11034  if(Link0Squares <= Link1Squares)
11035  {
11036  Utilities->CallLogPop(1851);
11037  return(0);
11038  }
11039  else
11040  {
11041  Utilities->CallLogPop(1852);
11042  return(1);
11043  }
11044 }
11045 
11046 // ---------------------------------------------------------------------------
11047 
11048 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11049 {
11050  // element can be points or any other type
11051  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11052  AnsiString(LinkPos));
11053  Derail = false;
11054  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11055 
11056  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11057  {
11058  if(TE.Attribute == 0)
11059  {
11060  Utilities->CallLogPop(663);
11061  return(1); // Att == 0 & ExitPos == 1 represent straight
11062  }
11063  else
11064  {
11065  Utilities->CallLogPop(664);
11066  return(3); // Att == 1 & ExitPos == 3 represent diverging
11067  }
11068  }
11069  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11070  {
11071  if((LinkPos == 1) && (TE.Attribute == 0))
11072  {
11073  Utilities->CallLogPop(665);
11074  return(0); // Att == 0 represents straight
11075  }
11076  else if(LinkPos == 1)
11077  {
11078  Derail = true;
11079  Utilities->CallLogPop(666);
11080  return(0);
11081  }
11082  else if((LinkPos == 3) && (TE.Attribute == 1))
11083  {
11084  Utilities->CallLogPop(667);
11085  return(0);
11086  }
11087  else if(LinkPos == 3)
11088  {
11089  Derail = true;
11090  Utilities->CallLogPop(668);
11091  return(0);
11092  }
11093  }
11094  else if(LinkPos == 0)
11095  {
11096  Utilities->CallLogPop(669);
11097  return(1);
11098  }
11099  else if(LinkPos == 1)
11100  {
11101  Utilities->CallLogPop(670);
11102  return(0);
11103  }
11104  else if(LinkPos == 2)
11105  {
11106  Utilities->CallLogPop(671);
11107  return(3);
11108  }
11109  else if(LinkPos == 3)
11110  {
11111  Utilities->CallLogPop(672);
11112  return(2);
11113  }
11114  throw Exception("Error, failure in GetExitPos"); // should never reach here
11115 }
11116 
11117 // ----------------------------------------------------------------------------
11118 
11120 {
11121  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11122  LCVector.clear();
11123  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11124  {
11125  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11126  {
11127  LCVector.push_back(x);
11128  }
11129  }
11130  Utilities->CallLogPop(1931);
11131  return;
11132 }
11133 
11134 // ---------------------------------------------------------------------------
11135 
11136 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11137 /*
11138  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11139  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11140  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11141  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11142 */
11143 {
11144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11145  AnsiString(Link));
11146  bool FoundFlag;
11147 
11148  TrainID = -1;
11149  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11150 
11151  if(!FoundFlag)
11152  {
11153  Utilities->CallLogPop(2001);
11154  return(false);
11155  }
11156  TTrackElement TE = TrackElementAt(882, VecPos);
11157 
11158  TrainID = TE.TrainIDOnElement;
11159  if(TE.TrackType == Bridge)
11160  {
11161  if(TE.TrainIDOnElement > -1)
11162  {
11163  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11164  {
11165  TrainID = TE.TrainIDOnBridgeTrackPos01;
11166  }
11167  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11168  {
11169  TrainID = TE.TrainIDOnBridgeTrackPos23;
11170  }
11171  else
11172  {
11173  TrainID = -1; // shouldn't ever reach here but be safe
11174  }
11175  }
11176  }
11177  if(TrainID == -1)
11178  {
11179  Utilities->CallLogPop(2002);
11180  return(false);
11181  }
11182 // now get the train
11183  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11184 
11185  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11186  {
11187  Utilities->CallLogPop(2003);
11188  return(true);
11189  }
11190  TrainID = -1;
11191  Utilities->CallLogPop(2004);
11192  return(false);
11193 }
11194 
11195 // ---------------------------------------------------------------------------
11196 
11197 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11198 /* New at v1.2.0
11199  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11200  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11201  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11202  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11203  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11204  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11205  Each of these is examined in turn for each route element in the relevant position.
11206 */
11207 {
11208  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11209  "," + AnsiString(DiagonalLinkNumber));
11210  TrainID = -1;
11211  TPrefDirElement TempPrefDirElement;
11212  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11213 
11214  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11215  {
11216  Utilities->CallLogPop(2027);
11217  return(true);
11218  }
11219  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11220  {
11221  Utilities->CallLogPop(2028);
11222  return(true);
11223  }
11224  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11225  {
11226  Utilities->CallLogPop(2029);
11227  return(true);
11228  }
11229  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11230  {
11231  Utilities->CallLogPop(2030);
11232  return(true);
11233  }
11234  Utilities->CallLogPop(2031);
11235  return(false);
11236 }
11237 
11238 // ---------------------------------------------------------------------------
11239 
11240 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11241 {
11242  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11243  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11244  TUserGraphicItem UGI;
11245  AnsiString JustFileName = "";
11246 
11247  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11248  {
11249  UGI = UserGraphicVectorAt(17, x);
11250  int LastDelim = UGI.FileName.LastDelimiter('\\');
11251  if(LastDelim == 0) // can't find it so skip this item
11252  {
11253  continue;
11254  }
11255  else
11256  {
11257  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11258  }
11259  Utilities->SaveFileString(VecFile, JustFileName);
11260  Utilities->SaveFileInt(VecFile, UGI.HPos);
11261  Utilities->SaveFileInt(VecFile, UGI.VPos);
11262  }
11263  Utilities->CallLogPop(2178);
11264 }
11265 
11266 // ---------------------------------------------------------------------------
11267 
11268 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11269 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11270 {
11271  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11272  int NumPlats = 0;
11273  TTrackElement TempElement;
11274  int TempInt;
11275 
11276  typedef std::list<int> TNamePosList;
11277  TNamePosList NamePosList;
11278  typedef TNamePosList::iterator TNPLIt;
11279  TNPLIt NPLIt;
11280  typedef std::list<int> TOnePlatList;
11281  TOnePlatList OnePlatList;
11282  typedef TOnePlatList::iterator TOPLIt;
11283  TOPLIt OPLIt;
11284 
11285  NamePosList.clear();
11286  OnePlatList.clear();
11287  for(unsigned int x = 0; x < TrackVector.size(); x++)
11288  {
11289  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11290  {
11291  NamePosList.push_back(x);
11292  }
11293  }
11294  //NamePosList complete
11295 
11296  if(!NamePosList.empty()) //first value for the loop examination
11297  {
11298  OnePlatList.push_back(NamePosList.back());
11299  NamePosList.pop_back(); //erase from NPV as done with it here
11300  }
11301  while(!OnePlatList.empty()) //loop to examine all linked elements
11302  {
11303  TempInt = OnePlatList.front();
11304  TempElement = TrackElementAt(989, TempInt);
11305 
11306  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11307  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11308  {
11309  OnePlatList.push_back(TempElement.Conn[0]);
11310  NamePosList.erase(NPLIt);
11311  }
11312  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11313  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11314  {
11315  OnePlatList.push_back(TempElement.Conn[1]);
11316  NamePosList.erase(NPLIt);
11317  }
11318  //here when loaded any connecting links into OnePlatList, so can erase the front element
11319  OnePlatList.erase(OnePlatList.begin());
11320  if(OnePlatList.empty())
11321  {
11322  NumPlats++; //finished with current linked elements so can increment NumPlats
11323  if(!NamePosList.empty())
11324  {
11325  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11326  NamePosList.pop_back(); //erase from NPV as done with it there
11327  }
11328  }
11329  }
11330  Utilities->CallLogPop(2218);
11331  return(NumPlats);
11332 }
11333 
11334 // ---------------------------------------------------------------------------
11335 // UserGraphic, PrefDir & Route functions
11336 // ---------------------------------------------------------------------------
11337 
11339 {
11340  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11341  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11342  {
11343  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11344  }
11345  Utilities->CallLogPop(2194);
11346  return(UserGraphicVector.at(At));
11347 }
11348 
11349 // ---------------------------------------------------------------------------
11350 
11351 int TOnePrefDir::LastElementNumber(int Caller) const
11352 {
11353  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11354  int RetVal = PrefDirVector.size() - 1;
11355 
11356  if(RetVal < 0)
11357  {
11358  throw Exception("Return value negative in call to LastElementNumber");
11359  }
11360  Utilities->CallLogPop(114);
11361  return(RetVal);
11362 }
11363 
11364 // ---------------------------------------------------------------------------
11366 {
11367  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11368  if(PrefDirVector.empty())
11369  {
11370  throw Exception("PrefDirVector empty in call to LastElementPtr");
11371  }
11372  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11373 
11374  Utilities->CallLogPop(115);
11375  return(RetIT);
11376 }
11377 
11378 // ---------------------------------------------------------------------------
11380 {
11381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11382  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11383  {
11384  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11385  }
11386  Utilities->CallLogPop(116);
11387  return(PrefDirVector.at(At));
11388 }
11389 
11390 // ---------------------------------------------------------------------------
11392 {
11393  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11394  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11395  {
11396  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11397  " in GetModifiablePrefDirElementAt");
11398  }
11399  Utilities->CallLogPop(117);
11400  return(PrefDirVector.at(At));
11401 }
11402 
11403 // ---------------------------------------------------------------------------
11405 {
11406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11407  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11408  {
11409  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11410  }
11411  Utilities->CallLogPop(118);
11412  return(SearchVector.at(At));
11413 }
11414 
11415 // ---------------------------------------------------------------------------
11417 {
11418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11419  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11420  {
11421  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11422  }
11423  Utilities->CallLogPop(119);
11424  return(SearchVector.at(At));
11425 }
11426 
11427 // ---------------------------------------------------------------------------
11428 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11429 /*
11430  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11431  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11432  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11433  set in later functions.
11434 */
11435 {
11436  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11437  ClearPrefDir();
11438  int TrackVectorPosition;
11439  TTrackElement TrackElement;
11440 
11441  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11442  {
11443  Utilities->CallLogPop(126);
11444  return(false);
11445  }
11446 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11447  if(TrackElement.TrackType == Points)
11448  {
11449  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11450  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11451  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11452  //best to prevent it to avoid problems
11453  Utilities->CallLogPop(127);
11454  return false;
11455  }
11456 */
11457  TPrefDirElement PrefDirElement(TrackElement);
11458 
11459  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11460  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11461  StorePrefDirElement(1, PrefDirElement); // enter first element
11462 // Note that ELink not set even if a buffer or continuation - these set in
11463 // ConvertPrefDirSearchVector after 2nd element added
11464 
11465  Utilities->CallLogPop(128);
11466  return(true);
11467 }
11468 
11469 // ---------------------------------------------------------------------------
11470 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11471 
11472 /*
11473  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11474  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11475  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11476  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11477  so that the calling function knows that the PrefDir is complete.
11478  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11479  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11480  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11481  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11482  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11483  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11484  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11485  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11486 */
11487 
11488 {
11489  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11490  FinishElement = false;
11491  int TrackVectorPosition;
11492 
11493  TotalSearchCount = 0;
11494  TTrackElement TrackElement, TempTrackElement;
11495 
11496  if(PrefDirVector.size() == 0)
11497  {
11498  Utilities->CallLogPop(129);
11499  return(false);
11500  }
11501  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11502  {
11503  Utilities->CallLogPop(130);
11504  return(false);
11505  }
11506 // set the search limits using the last stored element in PrefDirVector as the start point
11507 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11508 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11509 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11510 
11511  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11512 
11513  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11514  {
11515  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11516  SearchLimitHighH = TrackElement.HLoc + 15;
11517  }
11518  else
11519  {
11520  SearchLimitLowH = TrackElement.HLoc - 15;
11521  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11522  }
11523  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11524  {
11525  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11526  SearchLimitHighV = TrackElement.VLoc + 15;
11527  }
11528  else
11529  {
11530  SearchLimitLowV = TrackElement.VLoc - 15;
11531  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11532  }
11533 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11534  check & TotalSearchCounts check
11535  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11536  {
11537  ShowMessage("Unable to reach the selected element - too far ahead");
11538  Utilities->CallLogPop(1692);
11539  return false;
11540  }
11541 */
11542 // get last PrefDir element
11543  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11544  {
11545  // check if TrackElement adjacent to any of the 4 XLinkPos'
11546  for(int x = 0; x < 4; x++)
11547  {
11548  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11549  {
11550  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11551  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11552  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11553  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11554  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11555  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11556  // shouldn't ever get it in a serious railway though.
11557 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11558  }
11559  }
11560  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11561  {
11562  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11563  SearchVector.clear(); // use this & convert to set all PrefDir element values
11564  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11565  {
11567  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11568  {
11569  FinishElement = true;
11570  }
11571  Utilities->CallLogPop(131);
11572  return(true);
11573  }
11574  } // not an adjacent element
11575 
11576  // now check each of the 4 possible XLinkPos values
11577  for(int x = 0; x < 4; x++)
11578  {
11579  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11580  {
11581  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11582  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11583  SearchVector.clear();
11584  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11585  {
11587  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11588  {
11589  FinishElement = true;
11590  }
11591  Utilities->CallLogPop(132);
11592  return(true);
11593  }
11594  }
11595  } // here if checked all possible exits without success
11596  ShowMessage(
11597  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11598  Utilities->CallLogPop(133);
11599  return(false);
11600  }
11601 // dealt above with LastPrefDirElement being the start element (which can be points)
11602 
11603  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11604  .ELinkPos] == Lead)) // leading point
11605  {
11606  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11607  {
11608  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11609  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11610  // can't be buffers or gap if points
11611  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11612  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11613  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11614  SearchVector.clear();
11615  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11616  {
11618  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11619  {
11620  FinishElement = true;
11621  }
11622  Utilities->CallLogPop(134);
11623  return(true);
11624  }
11625  }
11626  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11627  {
11628  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11629  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11630  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11631  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11632  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11633  SearchVector.clear();
11634  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11635  {
11637  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11638  {
11639  FinishElement = true;
11640  }
11641  Utilities->CallLogPop(135);
11642  return(true);
11643  }
11644  }
11645 // above dealt with immediate finds for leading point,
11646 // now deal with ordinary searches for leading point
11647  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11648  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11649  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11650  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11651  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11652  SearchVector.clear();
11653  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11654  {
11656  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11657  {
11658  FinishElement = true;
11659  }
11660  Utilities->CallLogPop(136);
11661  return(true);
11662  }
11663  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11664  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11665  // note that CheckCount already increased to allow for XLinkPos & XLink
11666  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11667  SearchVector.clear();
11668  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11669  {
11671  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11672  {
11673  FinishElement = true;
11674  }
11675  Utilities->CallLogPop(137);
11676  return(true);
11677  }
11678 // here if failed to find match for leading point
11679  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11680  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11681  ShowMessage(
11682  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11683  Utilities->CallLogPop(138);
11684  return(false);
11685  }
11686 // leading point fully dealt with above
11687 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11688 // separately as covered in ordinary search.
11689 
11690  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11691  SearchVector.clear();
11692 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11693  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11694  {
11696  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11697  {
11698  FinishElement = true;
11699  }
11700  Utilities->CallLogPop(139);
11701  return(true);
11702  }
11703  ShowMessage(
11704  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11705  Utilities->CallLogPop(140);
11706  return(false); // failed to find required element
11707 }
11708 
11709 // ---------------------------------------------------------------------------
11710 
11711 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11712 /*
11713  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11714  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11715  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11716  Keep a count of entries in SearchVector during the current function call, so that this number can be
11717  erased for an unproductive branch search.
11718  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11719  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11720  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11721  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11722  If not any of above, store element in searchvector, set the new current element values from the
11723  SearchElement, then go back to the while loop for the next step in the search.
11724 */
11725 {
11726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11727  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11728  int VectorCount = 0;
11729 
11730  while(true)
11731  {
11732  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11733  {
11734  for(int x = 0; x < VectorCount; x++)
11735  {
11736  SearchVector.erase(SearchVector.end() - 1);
11737  }
11738  Utilities->CallLogPop(141);
11739  return(false);
11740  }
11741  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11742  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11743  TPrefDirElement SearchElement(NextTrackElement);
11744  SearchElement.TrackVectorPosition = NextPosition;
11745  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11746  SearchElement.ELinkPos = NextELinkPos;
11747  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11748  int NextXLinkPos;
11749  if(SearchElement.ELinkPos == 0)
11750  {
11751  NextXLinkPos = 1;
11752  }
11753  if(SearchElement.ELinkPos == 1)
11754  {
11755  NextXLinkPos = 0;
11756  }
11757  if(SearchElement.ELinkPos == 2)
11758  {
11759  NextXLinkPos = 3;
11760  }
11761  if(SearchElement.ELinkPos == 3)
11762  {
11763  NextXLinkPos = 2;
11764  }
11765  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11766  {
11767  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11768  // but may be buffers, continuation or gap
11769  SearchElement.XLinkPos = NextXLinkPos;
11770  }
11771 // can't set XLink or XLinkPos yet if the element is a leading point.
11772 // check if found it
11773  if(SearchElement.TrackVectorPosition == RequiredPosition)
11774  {
11775  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11776  VectorCount++; // not really needed but include for tidyness
11777  TotalSearchCount++;
11778  Utilities->CallLogPop(142);
11779  return(true);
11780  }
11781 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11782 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11783 // at a time - drop this
11784 /*
11785  if(PrefDirVector.size() > 200)
11786  {
11787  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11788  Utilities->CallLogPop(1419);
11789  return false;
11790  }
11791 */
11792 // check if a buffer or continuation
11793  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11794  {
11795  for(int x = 0; x < VectorCount; x++)
11796  {
11797  SearchVector.erase(SearchVector.end() - 1);
11798  }
11799  Utilities->CallLogPop(143);
11800  return(false);
11801  }
11802 // check if reached an earlier position on search PrefDir with same entry value
11803  for(unsigned int x = 0; x < SearchVector.size(); x++)
11804  {
11805  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11806  {
11807  for(int x = 0; x < VectorCount; x++)
11808  {
11809  SearchVector.erase(SearchVector.end() - 1);
11810  }
11811  Utilities->CallLogPop(144);
11812  return(false);
11813  }
11814  }
11815 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11816 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11817  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11818  {
11819  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11820  {
11821  for(int x = 0; x < VectorCount; x++)
11822  {
11823  SearchVector.erase(SearchVector.end() - 1);
11824  }
11825  Utilities->CallLogPop(1417);
11826  return(false);
11827  }
11828  }
11829 
11830 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11831 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11832 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11834  {
11835  for(int x = 0; x < VectorCount; x++)
11836  {
11837  SearchVector.erase(SearchVector.end() - 1);
11838  }
11839  Utilities->CallLogPop(1691);
11840  return(false);
11841  }
11842 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11843  if(SearchVector.size() > 150)
11844  {
11845  for(int x = 0; x < VectorCount; x++)
11846  {
11847  SearchVector.erase(SearchVector.end() - 1);
11848  }
11849  Utilities->CallLogPop(1418);
11850  return(false);
11851  }
11852 // check if reached a leading point
11853  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11854  {
11855 // push element with XLink set to position [1]
11856  SearchElement.XLink = SearchElement.Link[1];
11857  SearchElement.XLinkPos = 1;
11858  SearchVector.push_back(SearchElement);
11859  VectorCount++;
11860  TotalSearchCount++;
11861  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11862  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11863  // can't be used. NextTrackElement is the corresponding TTrackElement.
11864  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11865  {
11866  Utilities->CallLogPop(145);
11867  return(true);
11868  }
11869  else
11870  {
11871 // remove leading point with XLinkPos [1]
11872  SearchVector.erase(SearchVector.end() - 1);
11873  VectorCount--;
11874 // push element with XLink set to position [3]
11875  SearchElement.XLink = SearchElement.Link[3];
11876  SearchElement.XLinkPos = 3;
11877  SearchVector.push_back(SearchElement);
11878  VectorCount++;
11879  TotalSearchCount++;
11880 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11881  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11882  {
11883  Utilities->CallLogPop(146);
11884  return(true);
11885  }
11886  else
11887  {
11888  for(int x = 0; x < VectorCount; x++)
11889  {
11890  SearchVector.erase(SearchVector.end() - 1);
11891  }
11892  Utilities->CallLogPop(147);
11893  return(false);
11894  }
11895  }
11896  } // if leading point
11897 
11898 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11899 // ready for next element on PrefDir
11900  SearchVector.push_back(SearchElement);
11901  VectorCount++;
11902  TotalSearchCount++;
11903  XLinkPos = NextXLinkPos;
11904  CurrentTrackElement = SearchElement;
11905  } // while(true)
11906 }
11907 
11908 // ---------------------------------------------------------------------------
11909 
11911 /*
11912  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11913  for each element on the search PrefDir, though if the last element is a leading point
11914  then the final XLink won't be set.
11915  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11916  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11917  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11918 */
11919 {
11920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11921  if(SearchVector.size() == 0)
11922  {
11923  throw Exception("Error, SearchVector empty");
11924  }
11925 // get first SearchElement in order to set last PrefDirelement
11926  TPrefDirElement SearchElement = SearchVector.at(0);
11927 
11928 // set last PrefDir element XLink & ELink values if not already set
11929 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11930  for(int x = 0; x < 4; x++)
11931  {
11932  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11933  {
11934  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11935  {
11936  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
11937  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
11938  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
11939  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
11940  }
11941  int ELinkPos;
11942  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
11943  {
11944  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
11945  }
11946  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
11947  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
11948  {
11949  ELinkPos = 0;
11950  }
11951  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
11952  {
11953  ELinkPos = 3;
11954  }
11955  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
11956  {
11957  ELinkPos = 2;
11958  }
11959  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
11960  {
11961  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
11962  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
11963  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
11964  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
11965  }
11966  break; // no point going any further
11967  }
11968  }
11969 // set EXNumber for last PrefDir element, unless already set
11970 // won't be set if was first element or a leading point
11971  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
11972  {
11973 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
11974  int EXArray[32][2] = {
11975  {4,6},{2,8}, //horizontal & vertical
11976  {2,4},{6,2},{8,6},{4,8}, //sharp curves
11977  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
11978  {1,9},{3,7} //forward & reverse diagonals
11979 */
11980 
11981  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
11982  {
11983  throw Exception("Error in EntryExitNumber 1");
11984  }
11985  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
11986  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
11987  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
11988  }
11989 // Last PrefDir element now complete
11990 
11991 // construct remaining PrefDir elements from searchvector
11992  for(unsigned int x = 0; x < SearchVector.size(); x++)
11993  {
11994  SearchElement = SearchVector.at(x);
11995  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
11996  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
11997  PrefDirElement.ELink = SearchElement.ELink;
11998  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
11999  PrefDirElement.XLink = SearchElement.XLink;
12000  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12001 // if XLink & XLinkPos not set don't account for them in CheckCount
12002  if(PrefDirElement.XLink == -1)
12003  {
12004  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12005  }
12006  // & TrackVectorPosition
12007  else
12008  {
12009  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12010  }
12011  // XLink, XLinkPos, TrackVectorPosition
12012 
12013 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12014  if(PrefDirElement.XLink != -1)
12015  {
12016  if(!(PrefDirElement.EntryExitNumber()))
12017  {
12018  throw Exception("Error in EntryExitNumber 2");
12019  }
12020  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12021  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12022  PrefDirElement.CheckCount++;
12023  // all values now incorporated if not a leading point
12024  }
12025 // store PrefDir element
12026  StorePrefDirElement(2, PrefDirElement);
12027  }
12028 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12029  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12030  {
12031  if(ValidatePrefDir(2))
12032  {
12033  ;
12034  } // error messages given within function
12035 
12036  }
12038 /* drop this, check dropped from search
12039  if(PrefDirVector.size() > 200)
12040  {
12041  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12042  }
12043 */
12044  Utilities->CallLogPop(148);
12045 }
12046 
12047 // ---------------------------------------------------------------------------
12048 
12049 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12050 /*
12051  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12052  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12053 */
12054 {
12055  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12056  LeadingPoints = false;
12057  if(PrefDirVector.empty())
12058  {
12059  Utilities->CallLogPop(1786);
12060  return(false); // should never be empty but allow for it for safety
12061  }
12062  if(PrefDirVector.size() == 1)
12063  {
12064  Utilities->CallLogPop(149);
12065  return(false); // can't end if only one element
12066  }
12067 /*
12068  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12069  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12070  {
12071  Utilities->CallLogPop(150);
12072  return true;
12073  }
12074 */
12075 // allow for anything but leading points
12076  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12077  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12078  {
12079  Utilities->CallLogPop(1776);
12080  return(true);
12081  }
12082  else
12083  {
12084  LeadingPoints = true;
12085  Utilities->CallLogPop(151);
12086  return(false);
12087  }
12088 }
12089 
12090 // ---------------------------------------------------------------------------
12091 
12093 /*
12094  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12095  and that every element is connected to the next element
12096 */
12097 {
12098  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12099  int Position;
12100  AnsiString ErrorString;
12101  bool Error = false;
12102 
12103  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12104  {
12105  if(PrefDirVector.at(x).HLoc == -2000000000)
12106  {
12107  Error = true;
12108  ErrorString = "HLoc";
12109  Position = x;
12110  }
12111  if(PrefDirVector.at(x).VLoc == -2000000000)
12112  {
12113  Error = true;
12114  ErrorString = "VLoc";
12115  Position = x;
12116  }
12117  if(PrefDirVector.at(x).ELink == -1)
12118  {
12119  Error = true;
12120  ErrorString = "ELink";
12121  Position = x;
12122  }
12123  if(PrefDirVector.at(x).ELinkPos == -1)
12124  {
12125  Error = true;
12126  ErrorString = "ELinkPos";
12127  Position = x;
12128  }
12129  if(PrefDirVector.at(x).XLink == -1)
12130  {
12131  Error = true;
12132  ErrorString = "XLink";
12133  Position = x;
12134  }
12135  if(PrefDirVector.at(x).XLinkPos == -1)
12136  {
12137  Error = true;
12138  ErrorString = "XLinkPos";
12139  Position = x;
12140  }
12141  if(PrefDirVector.at(x).SpeedTag == 0)
12142  {
12143  Error = true;
12144  ErrorString = "Tag";
12145  Position = x;
12146  }
12147  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12148  {
12149  Error = true;
12150  ErrorString = "TrackVectorPosition";
12151  Position = x;
12152  }
12153  if(PrefDirVector.at(x).EXNumber == -1)
12154  {
12155  Error = true;
12156  ErrorString = "EXNumber";
12157  Position = x;
12158  }
12159  if(PrefDirVector.at(x).CheckCount != 9)
12160  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12161  {
12162  Error = true;
12163  ErrorString = "CheckCount";
12164  Position = x;
12165  }
12166 // extra checks
12167  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12168  {
12169  Error = true;
12170  ErrorString = "EntryGraphicPtr";
12171  Position = x;
12172  }
12173  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12174  {
12175  Error = true;
12176  ErrorString = "EntryDirectionGraphicPtr";
12177  Position = x;
12178  }
12179 // end of extra checks
12180  if(x > 0)
12181  {
12182  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12183  {
12184  Error = true;
12185  ErrorString = "Last XLink not connected to this element";
12186  Position = x;
12187  }
12188  }
12189  }
12190  if(Error)
12191  {
12192  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12193  }
12194  else
12195  {
12196  Utilities->CallLogPop(153);
12197  return(true);
12198  }
12199 }
12200 
12201 // ---------------------------------------------------------------------------
12202 
12203 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12204 /*
12205  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12206  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12207  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12208  or a leading point.
12209 */
12210 {
12211  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12212  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12213  {
12214  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12215  {
12216  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12217  {
12218  ErasePrefDirElementAt(1, PrefDirVecPos);
12219  }
12220  if(PrefDirVector.size() == 0)
12221  {
12222  Utilities->CallLogPop(154);
12223  return(true);
12224  }
12225  if(PrefDirVector.size() == 1)
12226  {
12227  PrefDirVector.at(x - 1).ELinkPos = -1;
12228  PrefDirVector.at(x - 1).ELink = -1;
12229  PrefDirVector.at(x - 1).XLinkPos = -1;
12230  PrefDirVector.at(x - 1).XLink = -1;
12231  PrefDirVector.at(x - 1).EXNumber = -1;
12232  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12233  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12234  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12235  Utilities->CallLogPop(155);
12236  return(true);
12237  }
12238  // here with truncate element not first element, so ELink & ELinkPos set
12239  // unset XLink & Pos if a leading point
12240  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12241  {
12242  PrefDirVector.at(x - 1).XLinkPos = -1;
12243  PrefDirVector.at(x - 1).XLink = -1;
12244  PrefDirVector.at(x - 1).EXNumber = -1;
12245  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12246  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12247  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12248  Utilities->CallLogPop(156);
12249  return(true);
12250  }
12251  Utilities->CallLogPop(157);
12252  return(true);
12253  }
12254  }
12255  Utilities->CallLogPop(158);
12256  return(false);
12257 }
12258 
12259 // ---------------------------------------------------------------------------
12260 
12261 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12262 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12263 /*
12264  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12265  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12266  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12267  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12268  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12269  displayed.
12270 */
12271 {
12272  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12273  AnsiString((short)BuildingPrefDir));
12274  int HPos, VPos;
12275 
12276  if(PrefDirSize() == 0)
12277  {
12278  Utilities->CallLogPop(159);
12279  return;
12280  }
12281  for(unsigned int x = 0; x < PrefDirSize(); x++)
12282  {
12283  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12284 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12285 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12286 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12287  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12288  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12289  // only the front half of which will be overplotted by the back of the train, then when the train is
12290  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12291  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12292  {
12293  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12294  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12295  {
12296  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12297  }
12298  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12299  // Route, no direction if a single element
12300  {
12301  if(x == 0)
12302  {
12303  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12304  }
12305  if(x == (PrefDirSize() - 1))
12306  {
12307  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12308  }
12309  }
12310  }
12311  }
12312 
12313 // set start & end element colours if building a PrefDir
12314  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12315  {
12316  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12317  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12318  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12319  // set last element colour
12320  if(PrefDirSize() > 1)
12321  {
12322  unsigned int LatestPos = PrefDirSize() - 1;
12323  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12324  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12325  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12326  }
12327  }
12328  Disp->Update();
12329  Utilities->CallLogPop(160);
12330 }
12331 
12332 // ---------------------------------------------------------------------------
12333 
12335 /*
12336  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12337  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12338 */
12339 {
12340  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12341  if(PrefDirSize() == 0)
12342  {
12343  Utilities->CallLogPop(1547);
12344  return;
12345  }
12346  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12347  bool FoundFlag;
12349  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12350 
12351  while(MMIT != PrefDir4MultiMap.end())
12352  {
12353  H = MMIT->first.first;
12354  V = MMIT->first.second;
12355  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12356  // always found in order, any missing have PrefDirPosx == -1
12357  if(PrefDirPos0 > -1)
12358  {
12359  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12360  }
12361  if(PrefDirPos1 > -1)
12362  {
12363  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12364  }
12365  if(PrefDirPos2 > -1)
12366  {
12367  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12368  }
12369  if(PrefDirPos3 > -1)
12370  {
12371  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12372  }
12373  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12374  {
12375  // need to plot all 4 in order to obtain all the direction graphics
12376  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12377  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12378  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12379  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12380  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12381  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12382  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12383  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12384  MMIT++;
12385  MMIT++;
12386  MMIT++;
12387  MMIT++;
12388  }
12389  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12390  {
12391  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12392  {
12393  // 0 & 1 constitute the bidirectional PrefDir
12394  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12395  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12396  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12397  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12398  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12399  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12400  MMIT++;
12401  MMIT++;
12402  MMIT++;
12403  }
12404  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12405  {
12406  // 0 & 2 constitute the bidirectional PrefDir
12407  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12408  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12409  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12410  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12411  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12412  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12413  MMIT++;
12414  MMIT++;
12415  MMIT++;
12416  }
12417  else
12418  {
12419  // 1 & 2 constitute the bidirectional PrefDir
12420  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12421  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12422  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12423  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12424  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12425  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12426  MMIT++;
12427  MMIT++;
12428  MMIT++;
12429  }
12430  }
12431  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12432  {
12433  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12434  {
12435  // 0 & 1 constitute the bidirectional PrefDir
12436  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12437  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12438  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12439  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12440  MMIT++;
12441  MMIT++;
12442  }
12443  else
12444  {
12445  // 2 unidirectional PrefDirs
12446  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12447  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12448  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12449  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12450  MMIT++;
12451  MMIT++;
12452  }
12453  }
12454  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12455  {
12456  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12457  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12458  MMIT++;
12459  }
12460  }
12461  Disp->Update();
12462  Utilities->CallLogPop(1548);
12463 }
12464 
12465 // ---------------------------------------------------------------------------
12466 
12467 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12468 {
12469  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12470  int TempInt;
12471 
12472  ClearPrefDir();
12473  int NumberOfPrefDirElements = 0;
12474 
12475  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12476  for(int x = 0; x < NumberOfPrefDirElements; x++)
12477  {
12478  VecFile >> TempInt; // TrackVectorPosition
12479  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12480  LoadPrefDirElement.TrackVectorPosition = TempInt;
12481  VecFile >> TempInt;
12482  LoadPrefDirElement.ELink = TempInt;
12483  VecFile >> TempInt;
12484  LoadPrefDirElement.ELinkPos = TempInt;
12485  VecFile >> TempInt;
12486  LoadPrefDirElement.XLink = TempInt;
12487  VecFile >> TempInt;
12488  LoadPrefDirElement.XLinkPos = TempInt;
12489  VecFile >> TempInt;
12490  LoadPrefDirElement.EXNumber = TempInt;
12491  VecFile >> TempInt;
12492  LoadPrefDirElement.CheckCount = TempInt;
12493  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12494  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12495  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12496  if(!(LoadPrefDirElement.IsARoute))
12497  {
12498  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12499  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12500  }
12501  else
12502  {
12503  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12504  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12505  LoadPrefDirElement.PrefDirRoute);
12506  }
12507  StorePrefDirElement(5, LoadPrefDirElement);
12508  Utilities->LoadFileString(VecFile); // marker
12509  }
12511  Utilities->CallLogPop(161);
12512 }
12513 
12514 // ---------------------------------------------------------------------------
12515 
12516 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12517 {
12518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12519  int TempInt;
12520 
12521  ClearPrefDir();
12522  int NumberOfPrefDirElements = 0;
12523 
12524  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12525  for(int x = 0; x < NumberOfPrefDirElements; x++)
12526  {
12527  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12528  VecFile >> TempInt; // TrackVectorPosition
12529  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12530  LoadPrefDirElement.TrackVectorPosition = TempInt;
12531  VecFile >> TempInt;
12532  LoadPrefDirElement.ELink = TempInt;
12533  VecFile >> TempInt;
12534  LoadPrefDirElement.ELinkPos = TempInt;
12535  VecFile >> TempInt;
12536  LoadPrefDirElement.XLink = TempInt;
12537  VecFile >> TempInt;
12538  LoadPrefDirElement.XLinkPos = TempInt;
12539  VecFile >> TempInt;
12540  LoadPrefDirElement.EXNumber = TempInt;
12541  VecFile >> TempInt;
12542  LoadPrefDirElement.CheckCount = TempInt;
12543  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12544  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12545  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12546  if(!(LoadPrefDirElement.IsARoute))
12547  {
12548  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12549  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12550  }
12551  else
12552  {
12553  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12554  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12555  LoadPrefDirElement.PrefDirRoute);
12556  }
12557  StorePrefDirElement(0, LoadPrefDirElement);
12558  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12559  }
12561  Utilities->CallLogPop(1509);
12562 }
12563 
12564 // ---------------------------------------------------------------------------
12565 
12566 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12567 /*
12568  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12569  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12570 */
12571 {
12572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12573  int TempInt;
12574  int NumberOfPrefDirElements = 0;
12575 
12576  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12577  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12578  {
12579  Utilities->CallLogPop(1152);
12580  return(false);
12581  }
12582  for(int x = 0; x < NumberOfPrefDirElements; x++)
12583  {
12584  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12585  {
12586  Utilities->CallLogPop(1766);
12587  return(false);
12588  }
12589  VecFile >> TempInt;
12590  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12591  {
12592  Utilities->CallLogPop(163);
12593  return(false);
12594  }
12595  VecFile >> TempInt;
12596  if((TempInt < -1) || (TempInt > 9)) // ELink
12597  {
12598  Utilities->CallLogPop(162);
12599  return(false);
12600  }
12601  VecFile >> TempInt;
12602  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12603  {
12604  Utilities->CallLogPop(164);
12605  return(false);
12606  }
12607  VecFile >> TempInt;
12608  if((TempInt < -1) || (TempInt > 9)) // XLink
12609  {
12610  Utilities->CallLogPop(165);
12611  return(false);
12612  }
12613  VecFile >> TempInt;
12614  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12615  {
12616  Utilities->CallLogPop(166);
12617  return(false);
12618  }
12619  VecFile >> TempInt;
12620  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12621  {
12622  Utilities->CallLogPop(167);
12623  return(false);
12624  }
12625  VecFile >> TempInt;
12626  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12627  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12628  // ELinkPos, XLink, XLinkPos & EXNumber
12629  {
12630  Utilities->CallLogPop(168);
12631  return(false);
12632  }
12633  VecFile >> TempInt;
12634  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12635  {
12636  Utilities->CallLogPop(1147);
12637  return(false);
12638  }
12639  VecFile >> TempInt;
12640  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12641  {
12642  Utilities->CallLogPop(1510);
12643  return(false);
12644  }
12645  VecFile >> TempInt;
12646  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12647  {
12648  Utilities->CallLogPop(1148);
12649  return(false);
12650  }
12651  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12652  {
12653  Utilities->CallLogPop(1700);
12654  return(false);
12655  }
12656  }
12657  Utilities->CallLogPop(169);
12658  return(true);
12659 }
12660 
12661 // ---------------------------------------------------------------------------
12662 
12663 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12664 {
12665  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12666  int NumberOfPrefDirElements = PrefDirVector.size();
12667 
12668  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12669  for(int y = 0; y < NumberOfPrefDirElements; y++)
12670  {
12671  VecFile << y << '\n'; // extra
12672  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12673  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12674  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12675  VecFile << PrefDirVector.at(y).XLink << '\n';
12676  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12677  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12678  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12679  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12680  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12681  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12682  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12683  {
12684  VecFile << "************" << '\0' << '\n'; // marker
12685  }
12686  else
12687  {
12688  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12689  }
12690  }
12691  Utilities->CallLogPop(170);
12692 }
12693 
12694 // ---------------------------------------------------------------------------
12695 
12696 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12697 {
12698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12699  int NumberOfSearchElements = SearchVector.size();
12700 
12701  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12702  for(int y = 0; y < NumberOfSearchElements; y++)
12703  {
12704  VecFile << y << '\n'; // extra
12705  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12706  VecFile << SearchVector.at(y).ELink << '\n';
12707  VecFile << SearchVector.at(y).ELinkPos << '\n';
12708  VecFile << SearchVector.at(y).XLink << '\n';
12709  VecFile << SearchVector.at(y).XLinkPos << '\n';
12710  VecFile << SearchVector.at(y).EXNumber << '\n';
12711  VecFile << SearchVector.at(y).CheckCount << '\n';
12712  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12713  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12714  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12715  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12716  {
12717  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12718  }
12719  else
12720  {
12721  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12722  }
12723  }
12724  Utilities->CallLogPop(1847);
12725 }
12726 
12727 // ---------------------------------------------------------------------------
12728 
12729 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12730 /*
12731  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12732  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12733 */
12734 {
12735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12736  AnsiString(VLoc));
12737  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12738 
12739  if(VecPos > -1)
12740  {
12741  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12742  }
12743  else
12744  {
12745  Utilities->CallLogPop(171);
12746  return;
12747  }
12748  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12749  if(VecPos > -1)
12750  {
12751  ErasePrefDirElementAt(3, VecPos);
12752  }
12753  else
12754  {
12755  Utilities->CallLogPop(172);
12756  return;
12757  }
12758  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12759  if(VecPos > -1)
12760  {
12761  ErasePrefDirElementAt(4, VecPos);
12762  }
12763  else
12764  {
12765  Utilities->CallLogPop(173);
12766  return;
12767  }
12768  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12769  if(VecPos > -1)
12770  {
12771  ErasePrefDirElementAt(5, VecPos);
12772  }
12773  else
12774  {
12775  Utilities->CallLogPop(174);
12776  return;
12777  }
12778  Utilities->CallLogPop(175);
12779 }
12780 
12781 // ---------------------------------------------------------------------------
12782 /*
12783  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12784  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12785 
12786  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12787  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12788  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12789  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12790  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12791  PrefDirVector to correspond to the new track layout.
12792 
12793  {
12794  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12795  if(PrefDirSize() == 0)
12796  {
12797  Utilities->CallLogPop(176);
12798  return;
12799  }
12800  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12801  {
12802  int TV = PrefDirVector.at(x).TrackVectorPosition;
12803  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12804  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12805  if(Track->BlankElementAt(0, TV))
12806  {
12807  ErasePrefDirElementAt(6, x);
12808  }
12809  //if was a blankelement at x then ConnELink and ConnXLink both -1
12810  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12811  {
12812  ErasePrefDirElementAt(7, x);
12813  }
12814  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12815  //needs to be erased once, but if don't use 'else' then will erase two elements
12816  //since 'x' will correspond to the element after the first erased element
12817  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12818  {
12819  ErasePrefDirElementAt(8, x);
12820  }
12821  }
12822  Utilities->CallLogPop(177);
12823  }
12824 */
12825 // ---------------------------------------------------------------------------
12826 
12827 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12828 /*
12829  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12830  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12831 */
12832 {
12833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12834  bool AlreadyPresent, FoundFlag;
12835  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12836 
12837  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12838  {
12839  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12840  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12841  AlreadyPresent = false;
12842  if(FoundFlag)
12843  {
12844  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12845  {
12846  AlreadyPresent = true;
12847  }
12848  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12849  {
12850  AlreadyPresent = true;
12851  }
12852  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12853  {
12854  AlreadyPresent = true;
12855  }
12856  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12857  {
12858  AlreadyPresent = true;
12859  }
12860  }
12861  if(!AlreadyPresent)
12862  {
12863  StorePrefDirElement(4, TempElement);
12864  }
12865  }
12867  Utilities->CallLogPop(178);
12868 }
12869 /* earlier brute force search
12870  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12871  {
12872  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12873  bool AlreadyPresent = false;
12874  for(unsigned int y = 0;y<PrefDirSize();y++)
12875  {
12876  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12877  }
12878  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12879  }
12880 */
12881 
12882 // ---------------------------------------------------------------------------
12883 
12885 /*
12886  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12887  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12888  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12889  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12890  positions are likely to have changed, so this function is called to reset all the necessary connections and
12891  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12892  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12893  shouldn't have changed.
12894 */
12895 {
12896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12897  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12898  {
12899  bool FoundFlag;
12900  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12901  if(FoundFlag)
12902  {
12903  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12904  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12905  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12906  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12907  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12908  for(unsigned int z = 0; z < 4; z++)
12909  {
12910  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12911  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12912  }
12913  }
12914  else
12915  {
12916  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12917  }
12918  }
12919  Utilities->CallLogPop(179);
12920 }
12921 
12922 // ---------------------------------------------------------------------------
12923 
12925 /*
12926  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12927 */
12928 {
12929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12930  bool DiscrepancyFound = false;
12931 
12932  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12933  {
12934  bool FoundFlag;
12935  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12936  if(FoundFlag)
12937  {
12938  TPrefDirElement PE = PrefDirVector.at(x);
12939  if(PE.TrackVectorPosition != VecPos)
12940  {
12941  DiscrepancyFound = true;
12942  break;
12943  }
12944  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12945  {
12946  DiscrepancyFound = true;
12947  break;
12948  }
12949  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12950  {
12951  DiscrepancyFound = true;
12952  break;
12953  }
12954  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
12955  {
12956  DiscrepancyFound = true;
12957  break;
12958  }
12959  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
12960  {
12961  DiscrepancyFound = true;
12962  break;
12963  }
12964  }
12965  else
12966  {
12967  DiscrepancyFound = true;
12968  }
12969  }
12970  if(DiscrepancyFound)
12971  {
12972  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
12973  ClearPrefDir(); // also clears multimap
12974  }
12975  Utilities->CallLogPop(1436);
12976 }
12977 
12978 // ---------------------------------------------------------------------------
12979 
12981 /*
12982  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
12983  return true for OK
12984 */
12985 {
12986  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
12987  bool DiscrepancyFound = false;
12988 
12989  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12990  {
12991  bool FoundFlag;
12992  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12993  if(FoundFlag)
12994  {
12995  TPrefDirElement PE = PrefDirVector.at(x);
12996  if(PE.TrackVectorPosition != VecPos)
12997  {
12998  DiscrepancyFound = true;
12999  }
13000  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13001  {
13002  DiscrepancyFound = true;
13003  break;
13004  }
13005  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13006  {
13007  DiscrepancyFound = true;
13008  break;
13009  }
13010  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13011  {
13012  DiscrepancyFound = true;
13013  break;
13014  }
13015  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13016  {
13017  DiscrepancyFound = true;
13018  break;
13019  }
13020  }
13021  else
13022  {
13023  DiscrepancyFound = true;
13024  }
13025  }
13026  Utilities->CallLogPop(1512);
13027  return(!DiscrepancyFound);
13028 }
13029 
13030 // ---------------------------------------------------------------------------
13031 
13032 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13033 /*
13034  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13035  turn and for the overall sizes.
13036 */
13037 {
13038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13039  bool FoundFlag = false;
13040  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13041 
13042  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13043  {
13044  TPrefDirElement CheckElement = PrefDirVector.at(a);
13045  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13046  if(!FoundFlag)
13047  {
13048  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13049  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13050  }
13051  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13052  {
13053  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13054  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13055  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13056  }
13057  }
13058  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13059  {
13060  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13061  + " Caller=" + (AnsiString)Caller);
13062  }
13063  Utilities->CallLogPop(180);
13064 }
13065 
13066 // ---------------------------------------------------------------------------
13067 
13068 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13069  int &PrefDirPos3)
13070 /*
13071  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13072  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
13073  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13074  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13075  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13076 */
13077 {
13078  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13079  AnsiString(VLoc));
13080  THVPair PrefDirMapKeyPair;
13081 
13082  PrefDirPos0 = -1;
13083  PrefDirPos1 = -1;
13084  PrefDirPos2 = -1;
13085  PrefDirPos3 = -1;
13086  FoundFlag = false;
13087  PrefDirMapKeyPair.first = HLoc;
13088  PrefDirMapKeyPair.second = VLoc;
13089  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13090 
13091  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13092  if(ItPair.first == ItPair.second) //none found
13093  {
13094  Utilities->CallLogPop(181);
13095  return;
13096  }
13097  else
13098  {
13099  FoundFlag = true;
13100  PrefDirPos0 = ItPair.first->second;
13101  ItPair.first++;
13102  if(ItPair.first == ItPair.second)
13103  {
13104  Utilities->CallLogPop(182); //only one found
13105  return;
13106  }
13107  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13108  {
13109  PrefDirPos1 = ItPair.first->second;
13110  }
13111  ItPair.first++;
13112  if(ItPair.first == ItPair.second)
13113  {
13114  Utilities->CallLogPop(183); //2 found
13115  return;
13116  }
13117  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13118  {
13119  PrefDirPos2 = ItPair.first->second;
13120  }
13121  ItPair.first++;
13122  if(ItPair.first == ItPair.second)
13123  {
13124  Utilities->CallLogPop(184); //3 found
13125  return;
13126  }
13127  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13128  {
13129  PrefDirPos3 = ItPair.first->second; //4 found
13130  }
13131  }
13132  Utilities->CallLogPop(185);
13133 }
13134 
13135 // ---------------------------------------------------------------------------
13136 
13137 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13138 {
13139  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13140  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13141  try
13142  {
13143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13144  + "," + AnsiString(LinkNumberPos));
13145  bool FoundFlag;
13146  int PD0, PD1, PD2, PD3;
13147  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13148  {
13149  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13150  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13151  PD0, PD1, PD2, PD3);
13152  if(!FoundFlag)
13153  {
13154  Utilities->CallLogPop(2282);
13155  return(false);
13156  }
13157  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13158  {
13159  if(PD0 > -1)
13160  {
13161  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13162  {
13163  LinkedPrefDirVectorNumber = PD0;
13164  Utilities->CallLogPop(2283);
13165  return(true);
13166  }
13167  }
13168  if(PD1 > -1)
13169  {
13170  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13171  {
13172  LinkedPrefDirVectorNumber = PD1;
13173  Utilities->CallLogPop(2284);
13174  return(true);
13175  }
13176  }
13177  }
13178  if(PD0 > -1)
13179  {
13180  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13181  {
13182  LinkedPrefDirVectorNumber = PD0;
13183  Utilities->CallLogPop(2285);
13184  return(true);
13185  }
13186  }
13187  if(PD1 > -1)
13188  {
13189  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13190  {
13191  LinkedPrefDirVectorNumber = PD1;
13192  Utilities->CallLogPop(2286);
13193  return(true);
13194  }
13195  }
13196  if(PD2 > -1)
13197  {
13198  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13199  {
13200  LinkedPrefDirVectorNumber = PD2;
13201  Utilities->CallLogPop(2287);
13202  return(true);
13203  }
13204  }
13205  if(PD3 > -1)
13206  {
13207  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13208  {
13209  LinkedPrefDirVectorNumber = PD3;
13210  Utilities->CallLogPop(2288);
13211  return(true);
13212  }
13213  }
13214  LinkedPrefDirVectorNumber = -1;
13215  Utilities->CallLogPop(2289);
13216  return(false);
13217  }
13218  else //buffer or continuation, no link at position 0 but not a failure
13219  {
13220  LinkedPrefDirVectorNumber = -1;
13221  Utilities->CallLogPop(2290);
13222  return(true);
13223  }
13224  }
13225  catch(const Exception &e) //non error catch
13226  {
13227  LinkedPrefDirVectorNumber = -1;
13228  Utilities->CallLogPop(2291);
13229  return(false);
13230  }
13231 }
13232 
13233 // ---------------------------------------------------------------------------
13234 
13236 {
13237  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13238  bool FoundFlag; //not used
13239  int PD0, PD1, PD2, PD3;
13240  //recover all PDs at the H & V of PDPtr
13241  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13242 
13243  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13244  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13245 
13246  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13247  {
13248  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13249  {
13250  Utilities->CallLogPop(2292);
13251  return(true);
13252  }
13253  }
13254  if(PD1 > -1)
13255  {
13256  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13257  {
13258  Utilities->CallLogPop(2293);
13259  return(true);
13260  }
13261  }
13262  if(PD2 > -1)
13263  {
13264  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13265  {
13266  Utilities->CallLogPop(2294);
13267  return(true);
13268  }
13269  }
13270  if(PD3 > -1)
13271  {
13272  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13273  {
13274  Utilities->CallLogPop(2295);
13275  return(true);
13276  }
13277  }
13278  Utilities->CallLogPop(2296);
13279  return(false);
13280 }
13281 
13282 // ---------------------------------------------------------------------------
13283 
13284 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13285 /*
13286  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13287 */
13288 {
13289  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13290  PrefDirVector.push_back(LoadPrefDirElement);
13291  THVPair PrefDir4MultiMapKeyPair;
13292  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13293 
13294  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13295  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13296  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13297  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13298  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13299 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13300  Utilities->CallLogPop(186);
13301 }
13302 
13303 // ---------------------------------------------------------------------------
13304 
13305 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13306 /*
13307  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13308  4MultiMap if they are greater than the erased value.
13309 */
13310 {
13311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13312  bool FoundFlag;
13313 
13314  if(!PrefDirVector.empty())
13315  {
13316  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13317  if(!FoundFlag)
13318  {
13319  throw Exception("Failed to find PrefDir4MultiMap erase element");
13320  }
13321  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13322  PrefDir4MultiMap.erase(EraseIt);
13323  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13325  }
13326  Utilities->CallLogPop(187);
13327 }
13328 
13329 // ---------------------------------------------------------------------------
13330 
13331 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13332 /*
13333  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13334  4MultiMap if they are greater than the erased value.
13335 */
13336 {
13337  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13338  AnsiString(ErasedElementNumber));
13339  if(!PrefDir4MultiMap.empty())
13340  {
13341  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13342  {
13343  if(MapPtr->second > ErasedElementNumber)
13344  {
13345  MapPtr->second--;
13346  }
13347  }
13348  }
13349  Utilities->CallLogPop(1450);
13350 }
13351 
13352 // ---------------------------------------------------------------------------
13353 
13354 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13355 /*
13356  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13357  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13358  nothing is found this is an error but the error message is given in the calling function.
13359 */
13360 {
13361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13362  FoundFlag = false;
13363  if(PrefDirVectorPosition >= PrefDirVector.size())
13364  {
13365  throw Exception("PrefDirVectorPosition out of range");
13366  }
13367  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13368  THVPair PrefDir4MultiMapKeyPair;
13369 
13370  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13371  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13372  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13373 
13374  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13375  if(ItPair.first == ItPair.second)
13376  {
13377  Utilities->CallLogPop(188);
13378  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13379  }
13380  else
13381  {
13382  if(ItPair.first->second == PrefDirVectorPosition)
13383  {
13384  FoundFlag = true;
13385  Utilities->CallLogPop(189);
13386  return(ItPair.first);
13387  }
13388  ItPair.first++;
13389  if(ItPair.first == ItPair.second)
13390  {
13391  Utilities->CallLogPop(190);
13392  return(ItPair.first); // nothing found
13393  }
13394  if(ItPair.first->second == PrefDirVectorPosition)
13395  {
13396  FoundFlag = true;
13397  Utilities->CallLogPop(191);
13398  return(ItPair.first);
13399  }
13400  ItPair.first++;
13401  if(ItPair.first == ItPair.second)
13402  {
13403  Utilities->CallLogPop(192);
13404  return(ItPair.first); // nothing found
13405  }
13406  if(ItPair.first->second == PrefDirVectorPosition)
13407  {
13408  FoundFlag = true;
13409  Utilities->CallLogPop(193);
13410  return(ItPair.first);
13411  }
13412  ItPair.first++;
13413  if(ItPair.first == ItPair.second)
13414  {
13415  Utilities->CallLogPop(194);
13416  return(ItPair.first); // nothing found
13417  }
13418  if(ItPair.first->second == PrefDirVectorPosition)
13419  {
13420  FoundFlag = true;
13421  Utilities->CallLogPop(195);
13422  return(ItPair.first);
13423  }
13424  }
13425  Utilities->CallLogPop(196);
13426  return(ItPair.first); // nothing found
13427 }
13428 
13429 // ---------------------------------------------------------------------------
13430 
13431 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13432 /*
13433  Although there may be up to four entries at one H & V position this function gets just one. It is
13434  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13435  at H & V.
13436 */
13437 {
13438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13439  THVPair PrefDir4MultiMapKeyPair;
13440 
13441  PrefDir4MultiMapKeyPair.first = HLoc;
13442  PrefDir4MultiMapKeyPair.second = VLoc;
13443  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13444 
13445  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13446  if(ItPair.first == ItPair.second) // nothing found
13447  {
13448  Utilities->CallLogPop(197);
13449  return(-1);
13450  }
13451  else
13452  {
13453  Utilities->CallLogPop(198);
13454  return(ItPair.first->second);
13455  }
13456 }
13457 
13458 // ---------------------------------------------------------------------------
13459 
13460 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13461 {
13462  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13463  bool ErasedFlag = false;
13464 
13465  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13466  {
13467  if(PrefDirSize() == 0)
13468  {
13469  Utilities->CallLogPop(1511);
13470  return;
13471  }
13472  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13473  {
13474  ErasedFlag = false;
13475  // use 'else' to ensure don't try to access an erased element
13476  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13477  {
13478  ErasePrefDirElementAt(11, x);
13479  ErasedFlag = true;
13480  }
13481  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13482  {
13483  ErasePrefDirElementAt(12, x);
13484  ErasedFlag = true;
13485  }
13486  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13487  {
13488  ErasePrefDirElementAt(13, x);
13489  ErasedFlag = true;
13490  }
13491  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13492  {
13493  ErasePrefDirElementAt(9, x);
13494  ErasedFlag = true;
13495  }
13496  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13497  {
13498  ErasePrefDirElementAt(10, x);
13499  ErasedFlag = true;
13500  }
13501  if(!ErasedFlag)
13502  {
13503  // don't use 'else' here as may be more than one that need decrementing
13504  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13505  {
13506  PrefDirVector.at(x).TrackVectorPosition--;
13507  }
13508  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13509  {
13510  PrefDirVector.at(x).Conn[0]--;
13511  }
13512  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13513  {
13514  PrefDirVector.at(x).Conn[1]--;
13515  }
13516  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13517  {
13518  PrefDirVector.at(x).Conn[2]--;
13519  }
13520  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13521  {
13522  PrefDirVector.at(x).Conn[3]--;
13523  }
13524  }
13525  }
13526  }
13527  Utilities->CallLogPop(1434);
13528 }
13529 
13530 // ---------------------------------------------------------------------------
13531 
13532 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13533 {
13534  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13535  OverallDistance = 0;
13536  OverallSpeedLimit = 0;
13537  LeadingPointsAtLastElement = false;
13538  if(PrefDirSize() == 0) // shouldn't be empty when this called
13539  {
13540  Utilities->CallLogPop(1491);
13541  return;
13542  }
13543  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13544  {
13545  LeadingPointsAtLastElement = true;
13546  Utilities->CallLogPop(1492);
13547  return;
13548  }
13549  for(unsigned int x = 0; x < PrefDirSize(); x++)
13550  {
13551  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13552  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13553  {
13554  OverallDistance += PrefDirElement.Length23;
13555  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13556  {
13557  if(x == 0)
13558  {
13559  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13560  }
13561  else
13562  {
13563  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13564  {
13565  OverallSpeedLimit = -1;
13566  }
13567  }
13568  }
13569  }
13570  else
13571  {
13572  OverallDistance += PrefDirElement.Length01;
13573  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13574  {
13575  if(x == 0)
13576  {
13577  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13578  }
13579  else
13580  {
13581  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13582  {
13583  OverallSpeedLimit = -1;
13584  }
13585  }
13586  }
13587  }
13588  }
13589  Utilities->CallLogPop(1529);
13590 }
13591 
13592 // ---------------------------------------------------------------------------
13593 
13594 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13595 {
13596  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13597  if(PrefDirSize() == 0)
13598  {
13599  Utilities->CallLogPop(1564);
13600  return;
13601  }
13602  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13603  bool FoundFlag;
13605  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13606 
13607  while(MMIT != PrefDir4MultiMap.end())
13608  {
13609  HLoc = MMIT->first.first;
13610  VLoc = MMIT->first.second;
13611  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13612  H = HLoc - Track->GetHLocMin();
13613  V = VLoc - Track->GetVLocMin();
13614  // always found in order, any missing have PrefDirPosx == -1
13615  if(PrefDirPos0 > -1)
13616  {
13617  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13618  }
13619  if(PrefDirPos1 > -1)
13620  {
13621  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13622  }
13623  if(PrefDirPos2 > -1)
13624  {
13625  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13626  }
13627  if(PrefDirPos3 > -1)
13628  {
13629  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13630  }
13631  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13632  {
13633  // need to plot all 4 in order to obtain all the direction graphics
13634  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13635  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13636  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13637  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13638  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13639  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13640  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13641  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13642  MMIT++;
13643  MMIT++;
13644  MMIT++;
13645  MMIT++;
13646  }
13647  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13648  {
13649  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13650  {
13651  // 0 & 1 constitute the bidirectional PrefDir
13652  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13653  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13654  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13655  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13656  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13657  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13658  MMIT++;
13659  MMIT++;
13660  MMIT++;
13661  }
13662  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13663  {
13664  // 0 & 2 constitute the bidirectional PrefDir
13665  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13666  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13667  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13668  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13669  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13670  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13671  MMIT++;
13672  MMIT++;
13673  MMIT++;
13674  }
13675  else
13676  {
13677  // 1 & 2 constitute the bidirectional PrefDir
13678  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13679  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13680  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13681  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13682  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13683  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13684  MMIT++;
13685  MMIT++;
13686  MMIT++;
13687  }
13688  }
13689  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13690  {
13691  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13692  {
13693  // 0 & 1 constitute the bidirectional PrefDir
13694  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13695  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13696  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13697  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13698  MMIT++;
13699  MMIT++;
13700  }
13701  else
13702  {
13703  // 2 unidirectional PrefDirs
13704  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13705  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13706  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13707  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13708  MMIT++;
13709  MMIT++;
13710  }
13711  }
13712  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13713  {
13714  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13715  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13716  MMIT++;
13717  }
13718  }
13719  Utilities->CallLogPop(1565);
13720 }
13721 
13722 // ---------------------------------------------------------------------------
13723 
13724 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13725 /*
13726  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13727  level crossing, signals with wrong direction set, or buffers.
13728 */
13729 {
13730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13731  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13732  bool FoundFlag;
13734  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13735 
13736  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13737  ElementIn.VLoc)))
13738  {
13739  Utilities->CallLogPop(1982);
13740  return(false);
13741  }
13742  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13743  {
13744  Utilities->CallLogPop(1983);
13745  return(false);
13746  }
13747  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13748  {
13749  Utilities->CallLogPop(1995);
13750  return(false);
13751  }
13752 // Now check that there is only a single prefdir set
13753  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13754 // always found in order, any missing have PrefDirPosx == -1
13755  if(PrefDirPos0 > -1)
13756  {
13757  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13758  }
13759  if(PrefDirPos1 > -1)
13760  {
13761  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13762  }
13763  if(PrefDirPos2 > -1)
13764  {
13765  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13766  }
13767  if(PrefDirPos3 > -1)
13768  {
13769  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13770  }
13771  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13772  {
13773  Utilities->CallLogPop(1984);
13774  return(false);
13775  }
13776  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13777  {
13778  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13779  {
13780  Utilities->CallLogPop(1985);
13781  return(false);
13782  }
13783  else
13784  {
13785  Utilities->CallLogPop(1986);
13786  return(true);
13787  }
13788  }
13789  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13790  {
13791  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13792  {
13793  Utilities->CallLogPop(1987);
13794  return(false);
13795  }
13796  else
13797  {
13798  Utilities->CallLogPop(1988);
13799  return(true);
13800  }
13801  }
13802  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13803  {
13804  if(PrefDirElement0.XLinkPos == EntryPos)
13805  {
13806  Utilities->CallLogPop(1989);
13807  return(false);
13808  }
13809  else
13810  {
13811  Utilities->CallLogPop(1990);
13812  return(true);
13813  }
13814  }
13815  else
13816  {
13817  Utilities->CallLogPop(1991);
13818  return(false); // none found
13819  }
13820 }
13821 
13822 // ---------------------------------------------------------------------------
13823 
13825 {
13826 /* //Added at v2.1.0
13827  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13828  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13829  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13830  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13831  and can be modelled better anyway.
13832 
13833  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
13834  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
13835  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13836  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13837  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13838  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13839 */
13840  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
13841  ElementIn.VLoc + "," + XLink);
13842  int TrackVecPos;
13843  bool TrackFoundFlag;
13844  TTrackElement TempTrackElement;
13845 
13846  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
13847  {
13848  Utilities->CallLogPop(2047);
13849  return(false);
13850  }
13851 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13852  if(XLink == 1)
13853  {
13854  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13855  if(TrackFoundFlag)
13856  {
13857  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
13858  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13859  {
13860  Utilities->CallLogPop(2048);
13861  return(true);
13862  }
13863  }
13864  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13865  if(TrackFoundFlag)
13866  {
13867  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
13868  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13869  {
13870  Utilities->CallLogPop(2049);
13871  return(true);
13872  }
13873  }
13874  }
13875 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13876  if(XLink == 3)
13877  {
13878  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13879  if(TrackFoundFlag)
13880  {
13881  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
13882  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13883  {
13884  Utilities->CallLogPop(2050);
13885  return(true);
13886  }
13887  }
13888  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13889  if(TrackFoundFlag)
13890  {
13891  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
13892  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13893  {
13894  Utilities->CallLogPop(2051);
13895  return(true);
13896  }
13897  }
13898  }
13899 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13900  if(XLink == 7)
13901  {
13902  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13903  if(TrackFoundFlag)
13904  {
13905  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
13906  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13907  {
13908  Utilities->CallLogPop(2052);
13909  return(true);
13910  }
13911  }
13912  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13913  if(TrackFoundFlag)
13914  {
13915  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
13916  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13917  {
13918  Utilities->CallLogPop(2053);
13919  return(true);
13920  }
13921  }
13922  }
13923 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13924  if(XLink == 9)
13925  {
13926  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13927  if(TrackFoundFlag)
13928  {
13929  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
13930  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13931  {
13932  Utilities->CallLogPop(2054);
13933  return(true);
13934  }
13935  }
13936  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13937  if(TrackFoundFlag)
13938  {
13939  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
13940  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13941  {
13942  Utilities->CallLogPop(2055);
13943  return(true);
13944  }
13945  }
13946  }
13947  Utilities->CallLogPop(2056);
13948  return(false);
13949 }
13950 
13951 // ---------------------------------------------------------------------------
13952 
13953 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
13954 {
13955 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
13956  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
13957  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
13958  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
13959  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
13960 */
13961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
13963  bool FoundFlag, ContFlag, FoundElements = false;
13964  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13965  TPrefDirElement NextElement;
13966 
13967  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
13968  {
13969  LastIteratorValue++;
13970  ContFlag = false;
13971  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
13972  {
13973  continue;
13974  }
13975  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
13976  {
13977  continue;
13978  }
13979 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
13980  // found a potential route start point
13981  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
13982  {
13983  continue;
13984  }
13985  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
13986  {
13987  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
13988  if(PDVIt->TrackType == Continuation)
13989  {
13990  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
13991  {
13992  continue;
13993  }
13994  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
13995  {
13996  continue;
13997  }
13998  }
13999  StartElement = *PDVIt;
14000 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14001  // diverging track on which there was no pref dir. See below for 2 required changes.
14002  }
14003  else
14004  {
14005  continue;
14006  }
14007  // now track along until find a signal or continuation, checking validity for each element
14008  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14009  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14010  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14011  if(PrefDirPos0 == -1) // no continuing prefdir
14012  {
14013  continue;
14014  }
14015  bool NextElementFoundFlag = false;
14016  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14017  {
14018  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14019  NextElementFoundFlag = true;
14020  }
14021  if(PrefDirPos1 > -1)
14022  {
14023  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14024  {
14025  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14026  NextElementFoundFlag = true;
14027  }
14028  }
14029  if(PrefDirPos2 > -1)
14030  {
14031  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14032  {
14033  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14034  NextElementFoundFlag = true;
14035  }
14036  }
14037  if(PrefDirPos3 > -1)
14038  {
14039  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14040  {
14041  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14042  NextElementFoundFlag = true;
14043  }
14044  }
14045  if(!NextElementFoundFlag)
14046  {
14047  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14048 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14049  }
14050  while(true)
14051  {
14052  // check validity
14053  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14054  {
14055  ContFlag = true;
14056  break;
14057  }
14058  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14059  {
14060  ContFlag = true;
14061  break;
14062  }
14063  // check if in a route, providing not a signal, as a signal might be at the start of a route
14064  if(NextElement.TrackType != SignalPost)
14065  {
14066  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14067  {
14068  ContFlag = true;
14069  break;
14070  }
14071  }
14072  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14073  // can't be a gound signal as would have failed the validity test
14074  {
14075  EndElement = NextElement;
14076  break;
14077  }
14078  // get the next element in the sequence
14079  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14080  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14081  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14082  if(PrefDirPos0 == -1) // no continuing prefdir
14083  {
14084  ContFlag = true;
14085  break;
14086  }
14087  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14088  {
14089  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14090  continue;
14091  }
14092  if(PrefDirPos1 > -1)
14093  {
14094  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14095  {
14096  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14097  continue;
14098  }
14099  }
14100  if(PrefDirPos2 > -1)
14101  {
14102  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14103  {
14104  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14105  continue;
14106  }
14107  }
14108  if(PrefDirPos3 > -1)
14109  {
14110  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14111  {
14112  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14113  continue;
14114  }
14115  }
14116  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14117  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14118  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14119  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14120  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14121  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14122  {
14123  ContFlag = true;
14124  break;
14125  }
14126  else
14127  {
14128  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14129  // could drop the bridge test but keep it to show the change history
14130  break;
14131 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14132  }
14133  }
14134  if(ContFlag)
14135  {
14136  continue;
14137  }
14138  // else have start and end elements set & all elements valid, so set up the route segment
14139  FoundElements = true;
14140  break;
14141  }
14142  if(FoundElements)
14143  {
14144  Utilities->CallLogPop(1992);
14145  return(true);
14146  }
14147  else
14148  {
14149  Utilities->CallLogPop(1993);
14150  return(false);
14151  }
14152 }
14153 
14154 // ---------------------------------------------------------------------------
14155 // TOneRoute
14156 // ---------------------------------------------------------------------------
14157 
14158 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14159 {
14160 /* General:
14161  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14162  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14163  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14164  route will use automatic signals or not.
14165  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14166  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14167  elements, so additional work is needed to complete all their members before they are ready for conversion into
14168  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14169  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14170  ConvertAndAdd.......
14171 */
14172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14173  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14174  ClearRoute();
14175  int TrackVectorPosition;
14176  TTrackElement TrackElement;
14177  TPrefDirElement FirstElement, LastElement;
14178 
14179  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14180  {
14181  Utilities->CallLogPop(199);
14182  return(false);
14183  }
14184  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14185  {
14186  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14187  Utilities->CallLogPop(1996);
14188  return(false);
14189  }
14190  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14191  {
14192  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14193  Utilities->CallLogPop(200);
14194  return(false);
14195  }
14196  if(Track->IsLCAtHV(18, HLoc, VLoc))
14197  {
14198  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14199  Utilities->CallLogPop(1909);
14200  return(false);
14201  }
14202 // check if selected a train & disallow if so
14203  if(TrackElement.TrainIDOnElement > -1)
14204  {
14205  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14206  Utilities->CallLogPop(202);
14207  return(false);
14208  }
14209 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14210  TPrefDirElement PrefDirElement;
14211  int LockedVectorNumber;
14212 
14213  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14214  {
14215  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14216  Utilities->CallLogPop(203);
14217  return(false);
14218  }
14219  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14220  {
14221  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14222  Utilities->CallLogPop(204);
14223  return(false);
14224  }
14226  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14227 // signal in an autosig route & follow with a non-autosig route
14228 
14229  TPrefDirElement BlankElement;
14230 
14231  StartElement1 = BlankElement;
14232  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14233 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14234  bool InPrefDirFlag = false;
14235 
14236  bool FoundFlag;
14237  int PrefDirPos0 = -1;
14238  int PrefDirPos1 = -1;
14239  int PrefDirPos2 = -1;
14240  int PrefDirPos3 = -1;
14241 
14243  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14244  int PrefDirVecPos[4] =
14245  {
14246  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14247  };
14248 
14249  for(int x = 0; x < 4; x++)
14250  {
14251  int b = PrefDirVecPos[x];
14252  if(b > -1)
14253  {
14254  // only allow the appropriate exit route to be searched
14255  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14256  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14257  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14258  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14259  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14260  {
14261  InPrefDirFlag = true;
14262  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14263  if(AutoSigsFlag)
14264  {
14265  StartElement1.AutoSignals = true;
14266  }
14267  StartElement1.PrefDirRoute = true;
14268  }
14269  }
14270  }
14271 
14272  if(!InPrefDirFlag)
14273  {
14275  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14276  Utilities->CallLogPop(205);
14277  return(false);
14278  }
14279 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14281  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14282 
14283  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14284  {
14285  throw Exception("Selection in two routes - should never happen!");
14286  }
14287  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14288  {
14289  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14290  {
14291  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14292  Utilities->CallLogPop(206);
14293  return(false);
14294  }
14295  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14296  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14297  {
14298  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14299  Utilities->CallLogPop(207);
14300  return(false);
14301  }
14302  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14303  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14304  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14305  {
14306  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14307  Utilities->CallLogPop(208);
14308  return(false);
14309  }
14310  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14312  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14313  if(AutoSigsFlag)
14314  {
14315  StartElement1.AutoSignals = true;
14316  }
14317  StartElement1.PrefDirRoute = true;
14319  Utilities->CallLogPop(209);
14320  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14321  }
14322 
14323  else // no route started
14324  {
14325 // check if selected position is adjacent to start or end of an existing route and disallow
14326  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14327  {
14328  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14329  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14330  {
14331  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14332  Utilities->CallLogPop(210);
14333  return(false);
14334  }
14335  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14336  {
14337  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14338  Utilities->CallLogPop(211);
14339  return(false);
14340  }
14341  }
14342 
14343 // check if it's adjacent to end of an an existing route,
14344  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14345  {
14347  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14348  {
14349  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14350  Utilities->CallLogPop(212);
14351  return(false);
14352  }
14353  }
14354  SearchVector.push_back(StartElement1);
14355  Utilities->CallLogPop(213);
14356  return(true);
14357  }
14358 }
14359 
14360 // ---------------------------------------------------------------------------
14361 
14362 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14363  IDInt &ReqPosRouteID, bool &PointsChanged)
14364 
14365 /*
14366  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14367 
14368  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14369  this being set to -1 for not used.
14370  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14371  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14372  Check correct type of element - signal/buffers/continuation.
14373  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14374  EndElement2 corresponding to the 2 possible PrefDir elements).
14375  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14376  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14377  linked forward to another route.
14378  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14379  for same position as start should cover this)
14380 
14381  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14382  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14383  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14384  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14385  If the search fails then return false.
14386  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14387  in the SearchVector to ensure it's entered as part of the new route.
14388  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14389  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14390  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14391  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14392  so return false, with an appropriate message if ConsecSignalsRoute set.
14393 */
14394 
14395 {
14396  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14397  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14398  int EndPosition; // the position selected
14399 
14400  Track->LCFoundInAutoSigsRoute = false;
14402  TotalSearchCount = 0;
14403  ReqPosRouteID = IDInt(-1); // default value for not used
14404  TTrackElement TrackElement;
14405  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14406  // given element as can't select 2-track elements
14407  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14408  {
14409  Utilities->CallLogPop(214);
14410  return(false);
14411  }
14412  if(Track->IsLCAtHV(19, HLoc, VLoc))
14413  {
14414  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14415  Utilities->CallLogPop(1908);
14416  return(false);
14417  }
14418 // cancel selection if on original start element
14419  if(EndPosition == StartRoutePosition)
14420  {
14421  Utilities->CallLogPop(215);
14422  return(false);
14423  }
14424  if(AutoSigsFlag)
14425  {
14426  if(TrackElement.TrackType == Buffers)
14427  {
14428  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14429  Utilities->CallLogPop(216);
14430  return(false);
14431  }
14432  }
14433  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14434  {
14435  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14436  Utilities->CallLogPop(217);
14437  return(false);
14438  }
14439 // check if train on element
14440  if(TrackElement.TrainIDOnElement > -1)
14441  {
14442  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14443  Utilities->CallLogPop(219);
14444  return(false);
14445  }
14446 // disallow if not in EveryPrefDir & set EndElement(s)
14447  bool InPrefDirFlag = false;
14448 
14449  bool FoundFlag;
14450  int PrefDirPos0 = -1;
14451  int PrefDirPos1 = -1;
14452  int PrefDirPos2 = -1;
14453  int PrefDirPos3 = -1;
14454 
14455  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14456  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14457  int PrefDirVecPos[4] =
14458  {
14459  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14460  };
14461 
14462  for(int x = 0; x < 4; x++)
14463  {
14464  int b = PrefDirVecPos[x];
14465  if(b > -1)
14466  {
14467  InPrefDirFlag = true;
14468  if(EndElement1.TrackVectorPosition == -1)
14469  {
14470  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14471  }
14472  else
14473  {
14474  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14475  }
14476  }
14477  }
14478  if(!InPrefDirFlag)
14479  {
14481  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14482  Utilities->CallLogPop(220);
14483  return(false);
14484  }
14485 // check if in an existing route - can't be a bridge so can use a simple 'find'
14486 // bool InRoute = false;
14488  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14489 
14490  if(RoutePair.first > -1)
14491  {
14492  if(RoutePair.second != 0) // not first element in existing route so no good
14493  {
14494  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14495  Utilities->CallLogPop(221);
14496  return(false);
14497  }
14498  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14499 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14500  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14501  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14502  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14503  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14504  {
14505  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14506  Utilities->CallLogPop(222);
14507  return(false);
14508  }
14509  EndElement1 = RouteElement;
14510  EndElement2 = BlankElement; // only need the route element
14511  EndPosition = EndElement1.TrackVectorPosition;
14512  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14513  }
14514 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14515 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14516 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14517 
14518  if(EndElement1.HLoc >= StartElement1.HLoc)
14519  {
14521  SearchLimitHighH = EndElement1.HLoc + 15;
14522  }
14523  else
14524  {
14525  SearchLimitLowH = EndElement1.HLoc - 15;
14527  }
14528  if(EndElement1.VLoc >= StartElement1.VLoc)
14529  {
14531  SearchLimitHighV = EndElement1.VLoc + 15;
14532  }
14533  else
14534  {
14535  SearchLimitLowV = EndElement1.VLoc - 15;
14537  }
14538 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14539  check & TotalSearchCounts check
14540  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14541  {
14542  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14543  Utilities->CallLogPop(1693);
14544  return false;
14545  }
14546 */
14547 // check if adjacent to start and disallow
14548  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14549  {
14551  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14552 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14553 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14554  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14555  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14556  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14557  {
14558  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14559  Utilities->CallLogPop(223);
14560  return(false);
14561  }
14562 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14563 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14564  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14565  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14566  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14567  {
14568  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14569  Utilities->CallLogPop(224);
14570  return(false);
14571  }
14572 // check if adjacent to end of a route & disallow
14574  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14575  {
14576  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14577  Utilities->CallLogPop(225);
14578  return(false);
14579  }
14580  }
14581 
14582 // check for same route as start element
14584  {
14585  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14586  Utilities->CallLogPop(226);
14587  return(false);
14588  }
14589 // check for a looping route
14590  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14591  {
14593  {
14594  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14595  Utilities->CallLogPop(1844);
14596  return(false);
14597  }
14598  }
14599 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14600 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14601 // and don't want to add it again
14602  if(StartSelectionRouteID > -1)
14603  {
14604  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14605  AutoSigsFlag))
14606  {
14607  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14608  if(PointsToBeChanged(5))
14609  {
14610  PointsChanged = true;
14611  }
14612  Utilities->CallLogPop(227);
14613  return(true);
14614  }
14615  else if(!Track->SuppressRouteFailMessage)
14616  {
14617  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14619  Utilities->CallLogPop(228);
14620  return(false);
14621  }
14622  }
14623  else
14624  {
14625 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14626 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14627 
14628 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14629 // note that a blank element will have XLinkPos set to -1
14630  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14631  {
14632  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14633  AutoSigsFlag))
14634  {
14635  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14636  if(PointsToBeChanged(6))
14637  {
14638  PointsChanged = true;
14639  }
14640  Utilities->CallLogPop(229);
14641  return(true);
14642  }
14643  else
14644  {
14646  {
14648  }
14649  Utilities->CallLogPop(230);
14650  return(false);
14651  }
14652  }
14653  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14654  {
14655  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14656  AutoSigsFlag))
14657  {
14658  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14659  if(PointsToBeChanged(7))
14660  {
14661  PointsChanged = true;
14662  }
14663  Utilities->CallLogPop(231);
14664  return(true);
14665  }
14666  else
14667  {
14669  {
14671  }
14672  Utilities->CallLogPop(232);
14673  return(false);
14674  }
14675  }
14676  // now start off in the best direction
14677  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14678  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14679  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14680  // unless new problems are found.
14681  if(StartElement1.XLinkPos == BestPos)
14682  {
14683  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14684  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14685  AutoSigsFlag))
14686  {
14687  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14688  if(PointsToBeChanged(8))
14689  {
14690  PointsChanged = true;
14691  }
14692  Utilities->CallLogPop(233);
14693  return(true);
14694  }
14695  else if(StartElement2.TrackVectorPosition > -1)
14696  {
14697  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14698  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14699  AutoSigsFlag))
14700  {
14701  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14702  if(PointsToBeChanged(9))
14703  {
14704  PointsChanged = true;
14705  }
14706  Utilities->CallLogPop(234);
14707  return(true);
14708  }
14709  }
14710  }
14711  else if(StartElement2.TrackVectorPosition > -1)
14712  {
14713  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14714  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14715  AutoSigsFlag))
14716  {
14717  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14718  if(PointsToBeChanged(10))
14719  {
14720  ;
14721  }
14722  {
14723  PointsChanged = true;
14724  }
14725  Utilities->CallLogPop(1857);
14726  return(true);
14727  }
14728  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14729  AutoSigsFlag))
14730  {
14731  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14732  if(PointsToBeChanged(11))
14733  {
14734  ;
14735  }
14736  {
14737  PointsChanged = true;
14738  }
14739  Utilities->CallLogPop(1858);
14740  return(true);
14741  }
14742  }
14743  else if(StartElement1.XLinkPos == (1 - BestPos))
14744  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14745  {
14746  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14747  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14748  AutoSigsFlag))
14749  {
14750  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14751  if(PointsToBeChanged(12))
14752  {
14753  PointsChanged = true;
14754  }
14755  Utilities->CallLogPop(1864);
14756  return(true);
14757  }
14758  }
14759  }
14761  {
14763  }
14764  Utilities->CallLogPop(235);
14765  return(false);
14766 }
14767 
14768 // ---------------------------------------------------------------------------
14769 
14770 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14771 {
14772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14773  if(PrefDirSize() == 0)
14774  {
14775  Utilities->CallLogPop(1704);
14776  return;
14777  }
14778  for(unsigned int x = 0; x < PrefDirSize(); x++)
14779  {
14780  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14781  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14782  {
14783  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14784  TempPrefDirElement.EXGraphicPtr);
14785  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14786  {
14787  if(x == 0)
14788  {
14789  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14790  TempPrefDirElement.EntryDirectionGraphicPtr);
14791  }
14792  if(x == (PrefDirSize() - 1))
14793  {
14794  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14795  TempPrefDirElement.EntryDirectionGraphicPtr);
14796  }
14797  }
14798  }
14799  }
14800 
14801  Utilities->CallLogPop(1705);
14802 }
14803 
14804 // ---------------------------------------------------------------------------
14805 
14806 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14807  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14808 
14809 /*
14810  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14811  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14812  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14813  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14814  Return false if any element (apart from RequiredPosition) is on an existing route.
14815  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14816 
14817  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14818  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14819  added during the function so as to leave it exactly as it was on entering, then return false).
14820  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14821  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14822  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14823  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14824  the route number that the searched-for element is the start of if any, and set to -1 if no
14825  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14826  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14827  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14828  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14829 
14830  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14831  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14832  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14833  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
14834  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
14835  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
14836  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14837  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
14838  or if train on element (unless a bridge & train on different track).
14839  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
14840  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
14841  a leading point where both trailing directions are in EveryPrefDir, if not fail.
14842  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
14843  AutoSignals member set if AutoSigsFlag set, then return true.
14844  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
14845 
14846  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
14847  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
14848  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
14849  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
14850  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
14851  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
14852  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
14853 
14854  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
14855  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
14856 */
14857 
14858 {
14859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
14860  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
14861  AnsiString((short)AutoSigsFlag));
14862  int VectorCount = 0;
14863  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
14864 
14865 // check for a fouled diagonal for first element. Added for v1.3.2
14866  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
14867  {
14868  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
14869  {
14870  for(int x = 0; x < VectorCount; x++)
14871  {
14872  SearchVector.erase(SearchVector.end() - 1);
14873  }
14874  Utilities->CallLogPop(2043);
14875  return(false);
14876  }
14877  }
14878  bool FirstPass = true;
14879 
14880  while(true)
14881  {
14882  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
14883  {
14884  Track->LCFoundInAutoSigsRoute = true;
14885  }
14886  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
14887  {
14888  for(int x = 0; x < VectorCount; x++)
14889  {
14890  SearchVector.erase(SearchVector.end() - 1);
14891  }
14892  Utilities->CallLogPop(1926);
14893  return(false);
14894  }
14895  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
14896  {
14897  for(int x = 0; x < VectorCount; x++)
14898  {
14899  SearchVector.erase(SearchVector.end() - 1);
14900  }
14901  Utilities->CallLogPop(236);
14902  return(false);
14903  }
14904  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
14905  // reached a valid signal that isn't the required position, user should always select the next
14906  // signal in a route so have to fail
14907  // won't affect recurive searches as for them the first pass element is always a point
14908  {
14909  for(int x = 0; x < VectorCount; x++)
14910  {
14911  SearchVector.erase(SearchVector.end() - 1);
14912  }
14913  Utilities->CallLogPop(237);
14914  return(false);
14915  }
14916  FirstPass = false;
14917  int NextPosition = PrefDirElement.Conn[XLinkPos];
14918  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
14919  TPrefDirElement SearchElement(NextTrackElement);
14920  SearchElement.TrackVectorPosition = NextPosition;
14921  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
14922  SearchElement.ELinkPos = NextELinkPos;
14923  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
14924  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
14925  int NextXLinkPos;
14926  if(SearchElement.ELinkPos == 0)
14927  {
14928  NextXLinkPos = 1;
14929  }
14930  if(SearchElement.ELinkPos == 1)
14931  {
14932  NextXLinkPos = 0;
14933  }
14934  if(SearchElement.ELinkPos == 2)
14935  {
14936  NextXLinkPos = 3;
14937  }
14938  if(SearchElement.ELinkPos == 3)
14939  {
14940  NextXLinkPos = 2;
14941  }
14942  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14943  {
14944  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14945 // note that may be buffers, continuation or gap
14946  SearchElement.XLinkPos = NextXLinkPos;
14947  }
14948 // can't set XLink or XLinkPos yet if the element is a leading point.
14949 
14950 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14951  for(unsigned int x = 0; x < SearchVector.size(); x++)
14952  {
14953  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14954  {
14955  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14956  // OK if a bridge & routes on different tracks
14957  {
14958  for(int x = 0; x < VectorCount; x++)
14959  {
14960  SearchVector.erase(SearchVector.end() - 1);
14961  }
14962  Utilities->CallLogPop(238);
14963  return(false);
14964  }
14965  }
14966  }
14967 
14968 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14969  TAllRoutes::TRouteElementPair SecondPair;
14971  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14972  if(RoutePair.first > -1)
14973  {
14974  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14975  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
14976  RoutePair.second).ELinkPos)))
14977  {
14978  // still OK if start of an expected route
14979  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
14980  {
14981  for(int x = 0; x < VectorCount; x++)
14982  {
14983  SearchVector.erase(SearchVector.end() - 1);
14984  }
14985  Utilities->CallLogPop(239);
14986  return(false); // only allow for start of an expected route
14987  }
14988  }
14989  }
14990  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14991  {
14992  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14993  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
14994  SecondPair.second).ELinkPos)))
14995  {
14996  // still OK if start of an expected route
14997  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
14998  {
14999  for(int x = 0; x < VectorCount; x++)
15000  {
15001  SearchVector.erase(SearchVector.end() - 1);
15002  }
15003  Utilities->CallLogPop(240);
15004  return(false); // only allow for start of an expected route
15005  }
15006  }
15007  }
15008 // check if a train on element, unless a bridge & train on different track
15009 // OK of same train as start element - no drop this
15010 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15011  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15012  {
15013  for(int x = 0; x < VectorCount; x++)
15014  {
15015  SearchVector.erase(SearchVector.end() - 1);
15016  }
15017  Utilities->CallLogPop(241);
15018  return(false);
15019  }
15020  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15021  {
15022  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
15023  {
15024  for(int x = 0; x < VectorCount; x++)
15025  {
15026  SearchVector.erase(SearchVector.end() - 1);
15027  }
15028  Utilities->CallLogPop(242);
15029  return(false);
15030  }
15031  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
15032  {
15033  for(int x = 0; x < VectorCount; x++)
15034  {
15035  SearchVector.erase(SearchVector.end() - 1);
15036  }
15037  Utilities->CallLogPop(243);
15038  return(false);
15039  }
15040  }
15041 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15042  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15043  {
15044  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15045  {
15046  for(int x = 0; x < VectorCount; x++)
15047  {
15048  SearchVector.erase(SearchVector.end() - 1);
15049  }
15050  Utilities->CallLogPop(244);
15051  return(false);
15052  }
15053  }
15054 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15055 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15056  bool InPrefDirFlag = false;
15057  PrefDirElement1 = BlankElement;
15058  PrefDirElement2 = BlankElement;
15059 
15060  bool FoundFlag;
15061  int PrefDirPos0 = -1;
15062  int PrefDirPos1 = -1;
15063  int PrefDirPos2 = -1;
15064  int PrefDirPos3 = -1;
15066  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15067  int PrefDirVecPos[4] =
15068  {
15069  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15070  };
15071  for(int x = 0; x < 4; x++)
15072  {
15073  int b = PrefDirVecPos[x];
15074  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15075  {
15076  InPrefDirFlag = true;
15077  if(PrefDirElement1.TrackVectorPosition == -1)
15078  {
15079  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15080  }
15081  else
15082  {
15083  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15084  }
15085  }
15086  }
15087  if(!InPrefDirFlag)
15088  {
15089  for(int x = 0; x < VectorCount; x++)
15090  {
15091  SearchVector.erase(SearchVector.end() - 1);
15092  }
15093  Utilities->CallLogPop(245);
15094  return(false);
15095  }
15096 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15097 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15098 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15100  {
15101  for(int x = 0; x < VectorCount; x++)
15102  {
15103  SearchVector.erase(SearchVector.end() - 1);
15104  }
15105  Utilities->CallLogPop(1690);
15106  return(false);
15107  }
15108 // check if found it
15109  if(SearchElement.TrackVectorPosition == RequiredPosition)
15110  {
15111 // need to ensure a signal/buffer/continuation
15112  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
15113  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
15114  {
15115  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15117  for(int x = 0; x < VectorCount; x++)
15118  {
15119  SearchVector.erase(SearchVector.end() - 1);
15120  }
15121  Utilities->CallLogPop(246);
15122  return(false);
15123  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15124 
15125  if(AutoSigsFlag)
15126  {
15127  PrefDirElement1.AutoSignals = true;
15128  }
15129  PrefDirElement1.PrefDirRoute = true;
15131  {
15133  {
15134  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15136  }
15137  for(int x = 0; x < VectorCount; x++)
15138  {
15139  SearchVector.erase(SearchVector.end() - 1);
15140  }
15141  Utilities->CallLogPop(1928);
15142  return(false);
15143  }
15144  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15145  VectorCount++; // not really needed but include for tidyness
15146  TotalSearchCount++;
15147  Utilities->CallLogPop(247);
15148  return(true);
15149  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15150 
15151 // check if a buffer or continuation (end of search on this leg if not found by now)
15152  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15153  {
15154  for(int x = 0; x < VectorCount; x++)
15155  {
15156  SearchVector.erase(SearchVector.end() - 1);
15157  }
15158  Utilities->CallLogPop(248);
15159  return(false);
15160  }
15161 // check if SearchVector exceeds a size of 150
15162  if(SearchVector.size() > 150)
15163  {
15164  for(int x = 0; x < VectorCount; x++)
15165  {
15166  SearchVector.erase(SearchVector.end() - 1);
15167  }
15168  Utilities->CallLogPop(1420);
15169  return(false);
15170  }
15171 // check if reached a leading point
15172  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15173  {
15174 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15175  int SearchPos1 = SearchElement.Attribute + 1;
15176  int SearchPos2;
15177  if(SearchPos1 == 2)
15178  {
15179  SearchPos1++;
15180  }
15181  if(SearchPos1 == 1)
15182  {
15183  SearchPos2 = 3;
15184  }
15185  else
15186  {
15187  SearchPos2 = 1;
15188  }
15189  SearchElement.XLink = SearchElement.Link[SearchPos1];
15190  SearchElement.XLinkPos = SearchPos1;
15191  InPrefDirFlag = false;
15192  if(SearchElement.XLink == PrefDirElement1.XLink)
15193  {
15194  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15195  InPrefDirFlag = true;
15196  }
15197  else if(SearchElement.XLink == PrefDirElement2.XLink)
15198  {
15199  SearchElement = PrefDirElement2;
15200  InPrefDirFlag = true;
15201  }
15202 // push element with XLink set to position [SearchPos1] if on a PrefDir
15203  if(InPrefDirFlag)
15204  {
15205 // check for a fouled diagonal for leading point for XLinkPos == 1)
15206  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15207  {
15208  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15209  {
15210  for(int x = 0; x < VectorCount; x++)
15211  {
15212  SearchVector.erase(SearchVector.end() - 1);
15213  }
15214  Utilities->CallLogPop(249);
15215  return(false);
15216  }
15217  }
15218  if(AutoSigsFlag)
15219  {
15220  SearchElement.AutoSignals = true;
15221  }
15222  SearchElement.PrefDirRoute = true;
15223  SearchVector.push_back(SearchElement);
15224  VectorCount++;
15225  TotalSearchCount++;
15226 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15227  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15228  AutoSigsFlag))
15229  {
15231  {
15233  {
15234  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15236  }
15237  for(int x = 0; x < VectorCount; x++)
15238  {
15239  SearchVector.erase(SearchVector.end() - 1);
15240  }
15241  Utilities->CallLogPop(1929);
15242  return(false);
15243  }
15244  Utilities->CallLogPop(250);
15245  return(true);
15246  }
15247  else
15248  {
15249 // remove leading point with XLinkPos [1]
15250  SearchVector.erase(SearchVector.end() - 1);
15251  VectorCount--;
15252  }
15253  }
15254 // XLink set to position [SearchPos2]
15255  SearchElement.XLink = SearchElement.Link[SearchPos2];
15256  SearchElement.XLinkPos = SearchPos2;
15257  if(SearchElement.XLink == PrefDirElement1.XLink)
15258  {
15259  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15260  }
15261  else if(SearchElement.XLink == PrefDirElement2.XLink)
15262  {
15263  SearchElement = PrefDirElement2;
15264  }
15265  else // failed to find a valid exit from the point
15266  {
15267  for(int x = 0; x < VectorCount; x++)
15268  {
15269  SearchVector.erase(SearchVector.end() - 1);
15270  }
15271  Utilities->CallLogPop(251);
15272  return(false);
15273  }
15274 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15275  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15276  {
15277  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15278  {
15279  for(int x = 0; x < VectorCount; x++)
15280  {
15281  SearchVector.erase(SearchVector.end() - 1);
15282  }
15283  Utilities->CallLogPop(252);
15284  return(false);
15285  }
15286  }
15287 // push element with XLink set to position [SearchPos2]
15288  if(AutoSigsFlag)
15289  {
15290  SearchElement.AutoSignals = true;
15291  }
15292  SearchElement.PrefDirRoute = true;
15293  SearchVector.push_back(SearchElement);
15294  VectorCount++;
15295  TotalSearchCount++;
15296 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15297  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15298  AutoSigsFlag))
15299  {
15301  {
15303  {
15304  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15306  }
15307  for(int x = 0; x < VectorCount; x++)
15308  {
15309  SearchVector.erase(SearchVector.end() - 1);
15310  }
15311  Utilities->CallLogPop(1930);
15312  return(false);
15313  }
15314  Utilities->CallLogPop(1592);
15315  return(true);
15316  }
15317  else
15318  {
15319  for(int x = 0; x < VectorCount; x++)
15320  {
15321  SearchVector.erase(SearchVector.end() - 1);
15322  }
15323  Utilities->CallLogPop(253);
15324  return(false);
15325  }
15326  } // if leading point
15327 
15328 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15329  SearchElement = PrefDirElement1;
15330  if(AutoSigsFlag)
15331  {
15332  SearchElement.AutoSignals = true;
15333  }
15334  SearchElement.PrefDirRoute = true;
15335  SearchVector.push_back(SearchElement);
15336  VectorCount++;
15337  TotalSearchCount++;
15338  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15339  PrefDirElement = SearchElement;
15340  } // while(true)
15341 }
15342 
15343 // ---------------------------------------------------------------------------
15344 
15345 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15346 {
15347 /*
15348  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15349  and the new or extended route created from that. Hence action varies depending on whether
15350  it is a completely new route, or an extension of an existing route at the beginning or the end.
15351  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15352  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15353 
15354  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15355  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15356  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15357  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15358  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15359  is decremented;
15360  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15361  from the existing route, then enter the new route into the AllRoutesVector;
15362  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15363  then enter the new route into the AllRoutesVector.
15364 
15365  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15366  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15367  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15368  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15369  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15370  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15371  for the new route and return;
15372  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15373  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15374 
15375  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15376  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15377  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15378 
15379 */
15380  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15381  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15382  if(SearchVector.size() < 1)
15383  {
15384  Utilities->CallLogPop(254);
15385  return;
15386  }
15388  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15389  {
15390  Utilities->CallLogPop(255);
15391  return;
15392  }
15393  TAllRoutes::TLockedRouteClass LockedRouteObject;
15394 
15396  unsigned int TruncatePrefDirPosition = 0;
15397 
15398  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15399 /* if have ReqPosRouteID:
15400  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15401  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15402  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15403  the existing route, then enter the new route into the AllRoutesVector
15404  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15405  then enter the new route into the AllRoutesVector
15406 */
15407  {
15410  {
15411  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15412  x++) // start at 1 as first element already in SearchVector
15413  {
15415  }
15416  // note that route numbers in map adjusted when ReqPos route cleared
15418  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15419  // set during ClearRouteDuringRouteBuildingAt
15421  {
15424  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15425  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15426  }
15427  }
15429  {
15431  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15432  }
15434  {
15435  SearchVector.pop_back();
15436  }
15437  }
15438  if(StartSelectionRouteID > -1)
15439 /* if have StartSelectionRouteID:
15440  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15441  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15442  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15443  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15444  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15445 */
15446  {
15448  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15449  {
15452  {
15453  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15454  for(unsigned int x = 0; x < SearchVector.size(); x++)
15455  {
15457  RouteNumber, GetFixedSearchElementAt(3, x));
15458  // find & store locked route truncate position in PrefDirVector for later use
15460  {
15461  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15462  {
15463  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15464  }
15465  }
15466  }
15468  {
15469  throw Exception("Error - failed to validate extended route for preferred route");
15470  }
15473  if(!AutoSigsFlag)
15474  {
15475  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15476  }
15477  // now add the reinstated locked route if required and set signals accordingly
15479  {
15480  LockedRouteObject.RouteNumber = RouteNumber;
15481  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15482  // now reset the signals for the locked route
15483  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15484  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15485  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15486  {
15487  // return all signals to red in route section to be truncated
15488  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15489  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15490  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15491  {
15492  TrackElement.Attribute = 0;
15493  Track->PlotSignal(10, TrackElement, Display);
15494  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15495  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15496  }
15497  }
15498  }
15499  AllRoutes->CheckMapAndRoutes(1); // test
15500  Utilities->CallLogPop(256);
15501  return;
15502  }
15504  {
15507  RouteElement.AutoSignals = true;
15508  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15509  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15510  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15511  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15512  }
15513  }
15514  else
15515  {
15517  }
15518 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15519 // AllRoutesVector hence nothing to do here
15520  }
15521  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15522  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15523  {
15524  throw Exception("Error - failed to validate single route for preferred route");
15525  }
15526  AllRoutes->StoreOneRoute(1, this);
15527  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15528  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15529  if(!AutoSigsFlag)
15530  {
15531  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15532  }
15533  AllRoutes->CheckMapAndRoutes(2); // test
15534  Utilities->CallLogPop(257);
15535 }
15536 
15537 // ---------------------------------------------------------------------------
15538 
15539 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15540 {
15541 /*
15542  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15543  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15544  & ensure signal/buffers/continuation.
15545  Note that can't select ConsecSignalsRoute for non-preferred routes.
15546  Check if train on element & disallow.
15547  Set default values for retained parameters:-
15548  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15549  StartSelectionRouteID = route that selection starts in if there is one;
15550 
15551  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15552  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15553  validity. This is just for safety reasons, the PrefDir values aren't used.
15554  StartElement1 & 2 are set to these PrefDirelements.
15555 
15556  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15557 
15558  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15559  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15560  blank StartElement2 (only want to use the route element), then return true.
15561  Check if adjacent to start or end of an existing route & disallow if so.
15562  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15563  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15564  SetRemainingSearchVectorValues().
15565  Finally add the required element to the SearchVector & return true.
15566 
15567 */
15568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15569  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15570  ClearRoute();
15571  int TrackVectorPosition;
15572  TTrackElement TrackElement;
15573  TPrefDirElement FirstElement, LastElement;
15574 
15575  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15576  {
15577  Utilities->CallLogPop(258);
15578  return(false);
15579  }
15580  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15581  {
15582  if(!Callon)
15583  {
15584  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15585  }
15586 // makes later adjacent route checks too complicated
15587  Utilities->CallLogPop(259);
15588  return(false);
15589  }
15590  if(Track->IsLCAtHV(21, HLoc, VLoc))
15591  {
15592  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15593  Utilities->CallLogPop(1910);
15594  return(false);
15595  }
15596 // check if selected a train & disallow if so
15597  if(TrackElement.TrainIDOnElement > -1)
15598  {
15599  if(!Callon)
15600  {
15601  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15602  }
15603  Utilities->CallLogPop(260);
15604  return(false);
15605  }
15606 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15607  TPrefDirElement PrefDirElement;
15608  int LockedVectorNumber;
15609 
15610  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15611  {
15612  if(!Callon)
15613  {
15614  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15615  }
15616  Utilities->CallLogPop(261);
15617  return(false);
15618  }
15619  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15620  {
15621  if(!Callon)
15622  {
15623  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15624  }
15625  Utilities->CallLogPop(262);
15626  return(false);
15627  }
15629 // AdjacentStartRouteNumber = -1;
15630  StartRoutePosition = TrackVectorPosition;
15631 // StartRouteSelectPosition = TrackVectorPosition;
15632 
15633  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15634  TPrefDirElement PrefDirElement2(TrackElement);
15635 
15636  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15637  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15638  TPrefDirElement BlankElement;
15639 
15640  PrefDirElement1.ELinkPos = 0;
15641  PrefDirElement1.XLinkPos = 1;
15642  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15643  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15644  if(!(PrefDirElement1.EntryExitNumber()))
15645  {
15646  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15647  // no need for bridge check as bridge selections not allowed
15648  }
15649  PrefDirElement1.CheckCount = 9;
15650  PrefDirElement2.ELinkPos = 1;
15651  PrefDirElement2.XLinkPos = 0;
15652  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15653  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15654  if(!(PrefDirElement2.EntryExitNumber()))
15655  {
15656  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15657  }
15658  PrefDirElement2.CheckCount = 9; // both now set
15659 
15660 // set StartElements to the above PrefDirElements
15661  StartElement1 = PrefDirElement1;
15662  StartElement2 = PrefDirElement2;
15663 
15664 // no PrefDir check needed as doesn't need to be in a PrefDir
15665 
15666 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15668  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15669 
15670  if(RoutePair.first > -1)
15671  {
15672  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15673  {
15674  if(!Callon)
15675  {
15676  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15677  }
15678  Utilities->CallLogPop(263);
15679  return(false);
15680  }
15681  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15682  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15683  {
15684  if(!Callon)
15685  {
15686  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15687  }
15688  Utilities->CallLogPop(264);
15689  return(false);
15690  }
15691  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15692  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15693  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15694  {
15695  if(!Callon)
15696  {
15697  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15698  }
15699  Utilities->CallLogPop(265);
15700  return(false);
15701  }
15702  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15704  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15705  StartElement2 = BlankElement; // only use the route element
15707  Utilities->CallLogPop(266);
15708  return(true); // all retained values set
15709  }
15710 
15711  else // selection not in an existing route
15712  {
15713 // check if it's adjacent to start of an an existing route,
15714  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15715  {
15716  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15717  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15718  {
15719  if(!Callon)
15720  {
15721  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15722  }
15723  Utilities->CallLogPop(267);
15724  return(false);
15725  }
15726  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15727  {
15728  if(!Callon)
15729  {
15730  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15731  }
15732  Utilities->CallLogPop(268);
15733  return(false);
15734  }
15735  }
15736 // check if it's adjacent to end of an an existing route,
15737  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15738  {
15740  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15741  {
15742  if(!Callon)
15743  {
15744  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15745  }
15746  Utilities->CallLogPop(269);
15747  return(false);
15748  }
15749  }
15750  // not in a route or adjacent to start or end of a route
15751  // in this case reset all variable values to -1 & CheckCount to 4
15752  StartElement1.ELink = -1;
15753  StartElement1.ELinkPos = -1;
15754  StartElement1.XLink = -1;
15755  StartElement1.XLinkPos = -1;
15756  StartElement1.EXNumber = -1;
15758  StartElement2 = BlankElement;
15759  SearchVector.push_back(StartElement1);
15760  Utilities->CallLogPop(270);
15761  return(true);
15762  }
15763 }
15764 
15765 // ---------------------------------------------------------------------------
15766 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15767 
15768 /*
15769  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15770 
15771  Declare the following integers:-
15772  EndPosition - TrackVectorPosition for the selection;
15773  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15774  Check if selection is a valid track element and set EndPosition.
15775  Cancel if select original start element, then check that not points, bridge or crossover.
15776  Check & fail if a train is present at the selection.
15777  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15778  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15779  No check needed for selection in EveryPrefDir.
15780  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15781  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15782  as don't need it if in a route.
15783  Check if selection adj to start or end of a route and disallow.
15784  Fail if select same route as starting route, though should already have failed earlier if this is so.
15785 
15786  If there's a StartSelectionRouteID then StartElement1 will be set to
15787  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15788  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15789  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15790  to add the new route to the AllRoutesVectorPtr.
15791  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15792  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15793  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15794  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15795  the search vector values and return.
15796  If not returned yet then have failed to find the required element so return false with no message.
15797 
15798 */
15799 
15800 {
15801 // get EndPosition
15802  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15803  AnsiString(VLoc));
15804  int EndPosition;
15805 
15806  TotalSearchCount = 0;
15807  ReqPosRouteID = IDInt(-1); // for not used
15808  TTrackElement TrackElement;
15809  TPrefDirElement BlankElement;
15810 
15811  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15812  {
15813  Utilities->CallLogPop(271);
15814  return(false);
15815  }
15816 // EndPosition = EndSelectPosition;
15817 // cancel selection if on original start element
15818  if(EndPosition == StartRoutePosition)
15819  {
15820  Utilities->CallLogPop(272);
15821  return(false);
15822  }
15823  if(Track->IsLCAtHV(22, HLoc, VLoc))
15824  {
15825  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15826  Utilities->CallLogPop(1911);
15827  return(false);
15828  }
15829  if((TrackElement.TrackType == Points) && !Callon)
15830  {
15831  if(!Callon)
15832  {
15833  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
15834  }
15835 // makes later adjacent route checks too complicated
15836  Utilities->CallLogPop(273);
15837  return(false);
15838  }
15839  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15840  {
15841  if(!Callon)
15842  {
15843  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
15844  }
15845 // makes later adjacent route checks too complicated
15846  Utilities->CallLogPop(1861);
15847  return(false);
15848  }
15849 // check if train on element
15850  if(TrackElement.TrainIDOnElement > -1)
15851  {
15852  if(!Callon)
15853  {
15854  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
15855  }
15856  Utilities->CallLogPop(274);
15857  return(false);
15858  }
15859 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
15860 // check passed)
15861  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15862  TPrefDirElement EndElement2(TrackElement);
15863 
15864  EndElement1.TrackVectorPosition = EndPosition;
15865  EndElement2.TrackVectorPosition = EndPosition;
15866  EndElement1.ELinkPos = 0;
15867  EndElement1.XLinkPos = 1;
15868  EndElement1.ELink = EndElement1.Link[0];
15869  EndElement1.XLink = EndElement1.Link[1];
15870  if(!(EndElement1.EntryExitNumber()))
15871  {
15872  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
15873  }
15874  EndElement1.CheckCount = 9;
15875  EndElement2.ELinkPos = 1;
15876  EndElement2.XLinkPos = 0;
15877  EndElement2.ELink = EndElement2.Link[1];
15878  EndElement2.XLink = EndElement2.Link[0];
15879  if(!(EndElement2.EntryExitNumber()))
15880  {
15881  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
15882  }
15883  EndElement2.CheckCount = 9; // both now set
15884 
15885 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15886 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15887 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15888 
15889  if(EndElement1.HLoc >= StartElement1.HLoc)
15890  {
15892  SearchLimitHighH = EndElement1.HLoc + 15;
15893  }
15894  else
15895  {
15896  SearchLimitLowH = EndElement1.HLoc - 15;
15898  }
15899  if(EndElement1.VLoc >= StartElement1.VLoc)
15900  {
15902  SearchLimitHighV = EndElement1.VLoc + 15;
15903  }
15904  else
15905  {
15906  SearchLimitLowV = EndElement1.VLoc - 15;
15908  }
15909 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15910  check & TotalSearchCounts check
15911  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15912  {
15913  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
15914  Utilities->CallLogPop(1694);
15915  return false;
15916  }
15917 */
15918 // don't need EveryPrefDir check for NonPreferredRoute
15919 
15920 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
15921 // bool InRoute = false;
15923  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15924 
15925  if(RoutePair.first > -1)
15926  {
15927  if(RoutePair.second != 0) // not first element in existing route so no good
15928  {
15929  if(!Callon)
15930  {
15931  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
15932  }
15933  Utilities->CallLogPop(275);
15934  return(false);
15935  }
15936  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
15937 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15938  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
15939  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15940  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15941  {
15942  if(!Callon)
15943  {
15944  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
15945  }
15946  Utilities->CallLogPop(276);
15947  return(false);
15948  }
15949  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
15950  EndElement2 = BlankElement; // only need the route element
15951  EndPosition = EndElement1.TrackVectorPosition;
15952  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
15953  }
15954 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
15955  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15956  {
15957  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
15958  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
15959 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15960 // && (AdjPosition != StartRoutePosition))
15961  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15962  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15963  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
15964  {
15965  if(!Callon)
15966  {
15967  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
15968  }
15969  Utilities->CallLogPop(277);
15970  return(false);
15971  }
15972 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15973 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
15974  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15975  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15976  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
15977  (AdjPosition != StartRoutePosition))
15978  {
15979  if(!Callon)
15980  {
15981  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
15982  }
15983  Utilities->CallLogPop(278);
15984  return(false);
15985  }
15986 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
15988  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
15989  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
15990  {
15991  if(!Callon)
15992  {
15993  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
15994  }
15995  Utilities->CallLogPop(279);
15996  return(false);
15997  }
15998  }
15999 
16000 // check for same route as start element
16002  {
16003  if(!Callon)
16004  {
16005  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16006  }
16007  Utilities->CallLogPop(280);
16008  return(false);
16009  }
16010 // check for a looping route
16011  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16012  {
16014  {
16015  if(!Callon)
16016  {
16017  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16018  }
16019  Utilities->CallLogPop(1845);
16020  return(false);
16021  }
16022  }
16023 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16024 // so search from this element.
16025 
16026  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16027 
16028  if(StartSelectionRouteID > -1)
16029  {
16030  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
16031  {
16033  if(PointsToBeChanged(0))
16034  {
16035  PointsChanged = true;
16036  }
16037  Utilities->CallLogPop(281);
16038  return(true);
16039  }
16040  else
16041  {
16042  if(!Callon)
16043  {
16045  }
16046  Utilities->CallLogPop(282);
16047  return(false);
16048  }
16049  }
16050  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16051  // search on the 2 ways out of the element, which has to be a 2-ended element
16052  {
16053 // check if selection adjacent to start element and if so use that
16054  if(SearchVector.at(0).Conn[0] == EndPosition)
16055  {
16056  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
16057  {
16059  if(PointsToBeChanged(1))
16060  {
16061  PointsChanged = true;
16062  }
16063  Utilities->CallLogPop(283);
16064  return(true);
16065  }
16066  else
16067  {
16068  if(!Callon)
16069  {
16071  }
16072  Utilities->CallLogPop(284);
16073  return(false);
16074  }
16075  }
16076  else if(SearchVector.at(0).Conn[1] == EndPosition)
16077  {
16078  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
16079  {
16081  if(PointsToBeChanged(2))
16082  {
16083  PointsChanged = true;
16084  }
16085  Utilities->CallLogPop(285);
16086  return(true);
16087  }
16088  else
16089  {
16090  if(!Callon)
16091  {
16093  }
16094  Utilities->CallLogPop(286);
16095  return(false);
16096  }
16097  }
16098  // now start off in the best direction
16099  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16100 
16101  if(SearchVector.at(0).Config[BestPos] != End)
16102  {
16103  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16104  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
16105  {
16107  if(PointsToBeChanged(3))
16108  {
16109  PointsChanged = true;
16110  }
16111  Utilities->CallLogPop(287);
16112  return(true);
16113  }
16114  }
16115  if(SearchVector.at(0).Config[1 - BestPos] != End)
16116  {
16117  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16118  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
16119  {
16121  if(PointsToBeChanged(4))
16122  {
16123  PointsChanged = true;
16124  }
16125  Utilities->CallLogPop(288);
16126  return(true);
16127  }
16128  }
16129  }
16130  if(!Callon)
16131  {
16133  }
16134  Utilities->CallLogPop(289);
16135  return(false);
16136 }
16137 
16138 // ---------------------------------------------------------------------------
16139 
16140 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
16141 /*
16142  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16143  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16144  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16145  Keep a count of entries in SearchVector during the current function call, so that this number can be
16146  erased for an unproductive branch search.
16147  First check (within the loop) whether XLink leads to an End & return false if so.
16148  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16149  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16150  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16151  train on element (unless a bridge & train on different track), or if element
16152  fouls an existing diagonal route (except if element is a leading point - these checked later).
16153  Then check if found required element. If so save it & return true.
16154  If not the required element check if buffer or continuation, & if so erase all searchvector
16155  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16156  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16157  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16158  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16159  When return true have 8 items from CheckCount established, only waiting for EXNumber
16160 */
16161 {
16162  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16163  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16164  int VectorCount = 0;
16165 
16166 // check for a fouled diagonal for first element. Added for v1.3.2
16167  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16168  (CurrentTrackElement.Link[XLinkPos] == 9))
16169  {
16170  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16171  {
16172  for(int x = 0; x < VectorCount; x++)
16173  {
16174  SearchVector.erase(SearchVector.end() - 1);
16175  }
16176  Utilities->CallLogPop(2044);
16177  return(false);
16178  }
16179  }
16180  while(true)
16181  {
16182  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16183  {
16184  for(int x = 0; x < VectorCount; x++)
16185  {
16186  SearchVector.erase(SearchVector.end() - 1);
16187  }
16188  Utilities->CallLogPop(1927);
16189  return(false);
16190  }
16191  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16192  {
16193  for(int x = 0; x < VectorCount; x++)
16194  {
16195  SearchVector.erase(SearchVector.end() - 1);
16196  }
16197  Utilities->CallLogPop(290);
16198  return(false);
16199  }
16200  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16201  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16202  TPrefDirElement SearchElement(NextTrackElement);
16203  SearchElement.TrackVectorPosition = NextPosition;
16204  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16205  SearchElement.ELinkPos = NextELinkPos;
16206  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16207  int NextXLinkPos;
16208  if(SearchElement.ELinkPos == 0)
16209  {
16210  NextXLinkPos = 1;
16211  }
16212  if(SearchElement.ELinkPos == 1)
16213  {
16214  NextXLinkPos = 0;
16215  }
16216  if(SearchElement.ELinkPos == 2)
16217  {
16218  NextXLinkPos = 3;
16219  }
16220  if(SearchElement.ELinkPos == 3)
16221  {
16222  NextXLinkPos = 2;
16223  }
16224  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16225  {
16226  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16227  // but may be buffers, continuation or gap
16228  SearchElement.XLinkPos = NextXLinkPos;
16229  }
16230 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16231 // can't set XLink or XLinkPos yet if the element is a leading point.
16232 
16233 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16234  for(unsigned int x = 0; x < SearchVector.size(); x++)
16235  {
16236  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16237  {
16238  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16239  // OK if it's a bridge & routes on different tracks
16240  {
16241  for(int x = 0; x < VectorCount; x++)
16242  {
16243  SearchVector.erase(SearchVector.end() - 1);
16244  }
16245  Utilities->CallLogPop(291);
16246  return(false);
16247  }
16248  }
16249  }
16250 
16251 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16252  TAllRoutes::TRouteElementPair SecondPair;
16254  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16255  if(RoutePair.first > -1)
16256  {
16257  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16258  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16259  RoutePair.second).ELinkPos)))
16260  {
16261  // still OK if start of an expected route
16262  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16263  {
16264  for(int x = 0; x < VectorCount; x++)
16265  {
16266  SearchVector.erase(SearchVector.end() - 1);
16267  }
16268  Utilities->CallLogPop(292);
16269  return(false); // only allow for start of an expected route
16270  }
16271  }
16272  }
16273  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16274  {
16275  // OK if it's a bridge & routes on different tracks
16276  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16277  SecondPair.second).ELinkPos)))
16278  {
16279  // still OK if start of an expected route
16280  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16281  {
16282  for(int x = 0; x < VectorCount; x++)
16283  {
16284  SearchVector.erase(SearchVector.end() - 1);
16285  }
16286  Utilities->CallLogPop(293);
16287  return(false); // only allow for start of an expected route
16288  }
16289  }
16290  }
16291 // check if a train on element, unless a bridge & train on different track
16292 // OK of same train as start element - no, drop this
16293 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16294  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16295  {
16296  for(int x = 0; x < VectorCount; x++)
16297  {
16298  SearchVector.erase(SearchVector.end() - 1);
16299  }
16300  Utilities->CallLogPop(294);
16301  return(false);
16302  }
16303  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16304  {
16305  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
16306  {
16307  for(int x = 0; x < VectorCount; x++)
16308  {
16309  SearchVector.erase(SearchVector.end() - 1);
16310  }
16311  Utilities->CallLogPop(295);
16312  return(false);
16313  }
16314  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
16315  {
16316  for(int x = 0; x < VectorCount; x++)
16317  {
16318  SearchVector.erase(SearchVector.end() - 1);
16319  }
16320  Utilities->CallLogPop(296);
16321  return(false);
16322  }
16323  }
16324 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16325  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16326  {
16327  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16328  {
16329  for(int x = 0; x < VectorCount; x++)
16330  {
16331  SearchVector.erase(SearchVector.end() - 1);
16332  }
16333  Utilities->CallLogPop(297);
16334  return(false);
16335  }
16336  }
16337 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16338 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16339 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16341  {
16342  for(int x = 0; x < VectorCount; x++)
16343  {
16344  SearchVector.erase(SearchVector.end() - 1);
16345  }
16346  Utilities->CallLogPop(1689);
16347  return(false);
16348  }
16349 // check if found it
16350  if(SearchElement.TrackVectorPosition == RequiredPosition)
16351  {
16352  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16353  {
16354  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16355  {
16356  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16357  }
16358  else
16359  {
16360  SearchElement.XLinkPos = 1;
16361  }
16362 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16363  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16364  }
16365  SearchVector.push_back(SearchElement);
16366  VectorCount++; // not really needed but include for tidyness
16367  TotalSearchCount++;
16368  Utilities->CallLogPop(298);
16369  return(true);
16370  }
16371 // Not the required element - check if a buffer or continuation
16372  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16373  {
16374  for(int x = 0; x < VectorCount; x++)
16375  {
16376  SearchVector.erase(SearchVector.end() - 1);
16377  }
16378  Utilities->CallLogPop(299);
16379  return(false);
16380  }
16381 // check if SearchVector exceeds a size of 150
16382  if(SearchVector.size() > 150)
16383  {
16384  for(int x = 0; x < VectorCount; x++)
16385  {
16386  SearchVector.erase(SearchVector.end() - 1);
16387  }
16388  Utilities->CallLogPop(1421);
16389  return(false);
16390  }
16391 // check if reached a leading point
16392  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16393  {
16394 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16395  int SearchPos1 = SearchElement.Attribute + 1;
16396  int SearchPos2;
16397  if(SearchPos1 == 2)
16398  {
16399  SearchPos1++;
16400  }
16401  if(SearchPos1 == 1)
16402  {
16403  SearchPos2 = 3;
16404  }
16405  else
16406  {
16407  SearchPos2 = 1;
16408  }
16409 // push element with XLink set to position [SearchPos1]
16410  SearchElement.XLink = SearchElement.Link[SearchPos1];
16411  SearchElement.XLinkPos = SearchPos1;
16412 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16413  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16414  {
16415  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16416  {
16417  for(int x = 0; x < VectorCount; x++)
16418  {
16419  SearchVector.erase(SearchVector.end() - 1);
16420  }
16421  Utilities->CallLogPop(300);
16422  return(false);
16423  }
16424  }
16425  SearchVector.push_back(SearchElement);
16426  VectorCount++;
16427  TotalSearchCount++;
16428 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16429 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16430 // recursive search as has to be a TTrackElement for non-preferred route searches
16431  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16432  {
16433  Utilities->CallLogPop(301);
16434  return(true);
16435  }
16436  else
16437  {
16438 // remove leading point with XLinkPos [SearchPos1]
16439  SearchVector.erase(SearchVector.end() - 1);
16440  VectorCount--;
16441 // push element with XLink set to position [SearchPos2]
16442  SearchElement.XLink = SearchElement.Link[SearchPos2];
16443  SearchElement.XLinkPos = SearchPos2;
16444 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16445  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16446  {
16447  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16448  {
16449  for(int x = 0; x < VectorCount; x++)
16450  {
16451  SearchVector.erase(SearchVector.end() - 1);
16452  }
16453  Utilities->CallLogPop(302);
16454  return(false);
16455  }
16456  }
16457  SearchVector.push_back(SearchElement);
16458  VectorCount++;
16459  TotalSearchCount++;
16460 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16461  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16462  {
16463  Utilities->CallLogPop(303);
16464  return(true);
16465  }
16466  else
16467  {
16468  for(int x = 0; x < VectorCount; x++)
16469  {
16470  SearchVector.erase(SearchVector.end() - 1);
16471  }
16472  Utilities->CallLogPop(304);
16473  return(false);
16474  }
16475  }
16476  } // if leading point
16477 
16478 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16479 // ready for next element on route
16480  SearchVector.push_back(SearchElement);
16481  VectorCount++;
16482  TotalSearchCount++;
16483  CurrentTrackElement = SearchElement;
16484  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16485  } // while(true)
16486 }
16487 
16488 // ---------------------------------------------------------------------------
16489 
16491 
16492 /*
16493  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16494  having all values set (since not necessarily on PrefDirs).
16495  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16496  (if it was the start), so these are checked first and set if necessary. All elements now have
16497  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16498  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16499  to set the route colour and direction graphics.
16500 */
16501 
16502 {
16503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16504  if(SearchVector.size() == 0)
16505  {
16506  throw Exception("Error, SearchVector empty");
16507  }
16508 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16509 // hence need to examine and update it if necessary
16510  TPrefDirElement SecondElement;
16511 
16512  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16513  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16514  // need above check or SecondElement will fail
16515  {
16516  SecondElement = SearchVector.at(1);
16517  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16518  for(int x = 0; x < 4; x++)
16519  {
16520  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16521  {
16522  if(SearchVector.at(0).XLink == -1) // i.e. not set
16523  {
16524  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16525  SearchVector.at(0).XLinkPos = x;
16526  }
16527  int ELinkPos;
16528  if(SearchVector.at(0).XLinkPos == 0)
16529  {
16530  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16531  }
16532  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16533  if(SearchVector.at(0).XLinkPos == 1)
16534  {
16535  ELinkPos = 0;
16536  }
16537  if(SearchVector.at(0).XLinkPos == 2)
16538  {
16539  ELinkPos = 3;
16540  }
16541  if(SearchVector.at(0).XLinkPos == 3)
16542  {
16543  ELinkPos = 2;
16544  }
16545  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16546  {
16547  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16548  SearchVector.at(0).ELinkPos = ELinkPos;
16549  }
16550  break; // no point going any further
16551  }
16552  }
16553  }
16554  for(unsigned int x = 0; x < SearchVector.size(); x++)
16555  {
16556  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16557 // set EXNumber
16558  if(!(SearchVector.at(x).EntryExitNumber()))
16559  {
16560  throw Exception("Error in EntryExitNumber 3");
16561  }
16562  SearchVector.at(x).CheckCount++;
16563 // all values now incorporated
16564  }
16565 
16566  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16567 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16568 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16569  Utilities->CallLogPop(305);
16570 }
16571 
16572 // ---------------------------------------------------------------------------
16573 
16575 
16576 /*
16577  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16578  AutoSigsRoute.
16579  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16580  beginning or the end.
16581  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16582  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16583  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16584  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16585  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16586  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16587  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16588 
16589  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16590  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16591  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16592  route at the start.
16593 
16594  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16595  for the new route and return.
16596 */
16597 
16598 {
16599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16600  AnsiString(ReqPosRouteID.GetInt()));
16601  if(SearchVector.size() < 1)
16602  {
16603  Utilities->CallLogPop(306);
16604  return;
16605  }
16606  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16607  if(!ValidatePrefDir(6))
16608  {
16609  Utilities->CallLogPop(307);
16610  return;
16611  }
16612  TAllRoutes::TLockedRouteClass LockedRouteObject;
16613 
16615  unsigned int TruncatePrefDirPosition = 0;
16616 
16617  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16618 /* if have ReqPosRouteID:
16619  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16620  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16621  then enter the new route into the AllRoutesVector
16622 */
16623  {
16625  {
16626  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16627  x++) // start at 1 as first element already in SearchVector
16628  {
16630  }
16631  // note that route numbers in map adjusted when ReqPos route cleared
16633  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16634  // set during ClearRouteDuringRouteBuildingAt)
16636  {
16639  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16640  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16641  }
16642  }
16644  {
16645  SearchVector.pop_back();
16646  }
16647  }
16648  if(StartSelectionRouteID > -1)
16649 /* if have StartSelectionRouteID:
16650  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16651  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16652 */
16653  {
16655  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16656  {
16658  {
16659  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16660  for(unsigned int x = 0; x < SearchVector.size(); x++)
16661  {
16663  RouteNumber, GetFixedSearchElementAt(7, x));
16664  // find & store locked route truncate position in PrefDirVector for later use
16666  {
16667  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16668  {
16669  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16670  }
16671  }
16672  }
16674  {
16675  throw Exception("Failed to validate extended route for nonpreferred route");
16676  }
16679  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16680  // now add the reinstated locked route if required and set signals accordingly
16681  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16682  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16683  // that I haven't thought of
16685  {
16686  LockedRouteObject.RouteNumber = RouteNumber;
16687  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16688  // now reset the signals for the locked route
16689  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16690  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16691  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16692  {
16693  // return all signals to red in route section to be truncated
16694  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16695  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16696  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16697  {
16698  TrackElement.Attribute = 0;
16699  Track->PlotSignal(11, TrackElement, Display);
16700  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16701  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16702  }
16703  }
16704  }
16705  AllRoutes->CheckMapAndRoutes(3); // test
16706  Utilities->CallLogPop(308);
16707  return;
16708  }
16709  }
16710  else
16711  {
16713  }
16714 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16715 // hence nothing to do here
16716  }
16717  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16718  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16719  {
16720  throw Exception("Failed to validate single route for nonpreferred route");
16721  }
16722  AllRoutes->StoreOneRoute(2, this);
16723  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16724  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16725  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16726  AllRoutes->CheckMapAndRoutes(4); // test
16727  Utilities->CallLogPop(309);
16728 }
16729 
16730 // ---------------------------------------------------------------------------
16731 
16732 void TOneRoute::SetRoutePoints(int Caller) const
16733 /*
16734  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16735  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16736  when they were created.
16737 */
16738 {
16739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16740  if(!PrefDirVector.empty())
16741  {
16742  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16743  {
16744  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16745  {
16746  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16747  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16748  }
16749  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16750  {
16751  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16752  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16753  }
16754  }
16755  }
16756  Utilities->CallLogPop(327);
16757 }
16758 
16759 // ---------------------------------------------------------------------------
16760 
16761 void TOneRoute::SetRouteSignals(int Caller) const
16762 /* Used for new train additions in AddTrain and in route setting
16763  Set the signals as follows:-
16764  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16765  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16766  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16767  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16768  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16769  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16770  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16771  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16772  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16773 
16774  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16775  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16776  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16777  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16778  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16779  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16780  as a green signal.
16781 */
16782 {
16783  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16784  if(!PrefDirVector.empty())
16785  {
16786  // get target Attribute value, check first if there is a forward linked route
16787  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16788  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16789  int ForwardLinkedRouteNumber, Attribute = 0;
16790  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16791  // Note that LastElement can't be points but can be linked to points
16792  {
16793  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16794  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16795  {
16796  if(ForwardLinkedRouteNumber > -1)
16797  {
16798  int NextForwardLinkedRouteNumber = -1;
16799  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16800  Attribute)))
16801  {
16802  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16803  }
16804  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16805  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16806  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16807  }
16808  }
16809  }
16810  int RouteNumber;
16811  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16812  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16813  if(RouteType != TAllRoutes::NoRoute)
16814  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16815  {
16816  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16817  }
16818  }
16819  Utilities->CallLogPop(1720);
16820 }
16821 
16822 // ---------------------------------------------------------------------------
16823 
16824 bool TOneRoute::PointsToBeChanged(int Caller) const
16825 {
16826  // true if at any point in SearchVector points have to be changed
16827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16828  if(!SearchVector.empty())
16829  {
16830  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16831  {
16832  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16833  {
16834  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
16835  {
16836  Utilities->CallLogPop(1717);
16837  return(true);
16838  }
16839  }
16840  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
16841  {
16842  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
16843  {
16844  Utilities->CallLogPop(1718);
16845  return(true);
16846  }
16847  }
16848  }
16849  }
16850  Utilities->CallLogPop(1719);
16851  return(false);
16852 }
16853 
16854 // ---------------------------------------------------------------------------
16855 
16856 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
16857 /*
16858  Works forward through the route until finds:-
16859  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16860  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
16861  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
16862  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16863  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
16864  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
16865  returns true;
16866  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
16867 */
16868 {
16869  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
16870  Attribute = 0;
16871  NextForwardLinkedRouteNumber = -1;
16872  for(unsigned int x = 0; x < PrefDirSize(); x++)
16873  {
16874  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
16875  if(PrefDirVector.at(x).TrackType == Bridge)
16876  {
16877  if(PrefDirVector.at(x).XLinkPos < 2)
16878  {
16879  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16880  }
16881  else
16882  {
16883  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16884  }
16885  }
16886  if(TrainID != -1)
16887  {
16888  Utilities->CallLogPop(328);
16889  return(true);
16890  }
16891  if(PrefDirVector.at(x).TrackType == Buffers)
16892  {
16893  Attribute = 1;
16894  Utilities->CallLogPop(329);
16895  return(true);
16896  }
16897  if(PrefDirVector.at(x).TrackType == Continuation)
16898  {
16899  Attribute = 3;
16900  Utilities->CallLogPop(330);
16901  return(true);
16902  }
16903  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16904  {
16905  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16906  {
16907  Attribute = 0;
16908  Utilities->CallLogPop(1950);
16909  return(true);
16910  }
16911  }
16912  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
16913  {
16914  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
16915  if(Attribute > 3)
16916  {
16917  Attribute = 3;
16918  }
16919  Utilities->CallLogPop(331);
16920  return(true);
16921  }
16922  if(x == PrefDirSize() - 1)
16923  {
16924  TPrefDirElement LastElement = PrefDirVector.at(x);
16925  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16926  {
16927  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
16928  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16929  {
16930  Attribute = 0;
16931  Utilities->CallLogPop(332);
16932  return(false);
16933  }
16934  }
16935  }
16936  }
16937  Utilities->CallLogPop(333);
16938  return(true);
16939 }
16940 
16941 // ---------------------------------------------------------------------------
16942 
16943 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
16944 /*
16945  This function is only called by TAllRoutes::SetAllRearwardsSignals.
16946 
16947  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16948  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16949  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16950  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16951  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16952  a route.
16953 
16954  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16955  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16956  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
16957  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
16958  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
16959  reference. If no train is found before the beginning of the route is reached the function returns true
16960 
16961  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
16962  and the next rearwards signal becomes yellow, although it's the first in the route
16963 */
16964 {
16965  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
16966  AnsiString(PrefDirVectorStartPosition));
16967  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
16968  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
16969 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
16970 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
16971  bool SkipContinuationAndBufferAttributeChange = false;
16972 
16973  if(!PrefDirVector.empty())
16974  {
16975  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
16976  {
16977  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16978  if(PrefDirPtr->TrackType == Bridge)
16979  {
16980  if(PrefDirPtr->XLinkPos < 2)
16981  {
16982  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16983  }
16984  else
16985  {
16986  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16987  }
16988  }
16989  if(TrainID != -1)
16990  {
16991  SkipContinuationAndBufferAttributeChange = true;
16992  break;
16993  }
16994  }
16995 
16998  {
16999  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17000  AutoSigVectorIT++)
17001  {
17002  if(!AllRoutes->AllRoutesVector.empty())
17003  {
17004  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17005  {
17006  SkipContinuationAndBufferAttributeChange = true;
17007  break;
17008  }
17009  }
17010  }
17011  }
17013  {
17014  SkipContinuationAndBufferAttributeChange = true;
17015  }
17016  if(!SkipContinuationAndBufferAttributeChange)
17017  {
17018  if(PrefDirVector.back().TrackType == Buffers)
17019  {
17020  Attribute = 1; // treat buffer as red signal
17021  }
17022  if(PrefDirVector.back().TrackType == Continuation)
17023  {
17024  Attribute = 3; // treat continuation as a green signal
17025  }
17026  }
17027  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17028  {
17029  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17030  if(PrefDirPtr->TrackType == Bridge)
17031  {
17032  if(PrefDirPtr->XLinkPos < 2)
17033  {
17034  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17035  }
17036  else
17037  {
17038  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17039  }
17040  }
17041  if(TrainID != -1)
17042  {
17043  Utilities->CallLogPop(334);
17044  return(false);
17045  }
17046  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17047  // the attribute to 0 so first signal behind the LC is red
17048  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17049  {
17050  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17051  {
17052  Attribute = 0;
17053  }
17054  }
17055 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17056 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17057  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17058  {
17059  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17060  PrefDirPtr->PrefDirRoute)
17061  {
17062 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17063 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17064  int LockedVecNum = 0; //not used
17065  TPrefDirElement DummyPrefDir; //not used
17066  bool KeepAttributeAt0ForLockedRoute = false;
17067  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17068  LockedVecNum))
17069  {
17070  Attribute = 0;
17071  KeepAttributeAt0ForLockedRoute = true;
17072  }
17073 //end of addition
17074  if(Attribute < 3)
17075  {
17076  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17077  }
17078  else
17079  {
17080  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17081  }
17082  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17083  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17084  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17085  {
17086  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17087  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17088  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17089  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17090  }
17091  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute)
17092  {
17093  Attribute++;
17094  }
17095  Display->Update(); // update after recent plots
17096  }
17097  }
17098  }
17099  }
17100  Utilities->CallLogPop(335);
17101  return(true);
17102 }
17103 
17104 // ---------------------------------------------------------------------------
17105 
17106 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17107 /*
17108  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17109  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17110  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17111  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17112  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17113  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17114  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17115  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17116 */
17117 {
17118  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17119  "," + AnsiString((short)PrefDirRoute));
17120  bool ElementInRoute = false;
17121  bool TrainOccupyingRoute = false;
17122 
17123  for(unsigned int b = 0; b < PrefDirSize(); b++)
17124  {
17125  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17126  {
17127  ElementInRoute = true;
17128  break;
17129  }
17130  }
17131  if(!ElementInRoute)
17132  {
17133  ReturnFlag = NotInRoute;
17134  Utilities->CallLogPop(336);
17135  return;
17136  }
17137 // it is in the route so continue, first look for a train or a flashing level crossing
17138  for(int b = PrefDirSize() - 1; b >= 0; b--)
17139  {
17140  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17141  if(PrefDirVector.at(b).TrackType == Bridge)
17142  {
17143  if(PrefDirVector.at(b).XLinkPos < 2)
17144  {
17145  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17146  }
17147  else
17148  {
17149  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17150  }
17151  }
17152  if(TrainID != -1)
17153  {
17154 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17155 // ReturnFlag = InRouteFalse;
17156 // Utilities->CallLogPop(337);
17157 // return;
17158 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17159  TrainOccupyingRoute = true; // train is forward of the truncate point
17160  }
17161  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17162  {
17163  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17164  ReturnFlag = InRouteFalse;
17165  Utilities->CallLogPop(1941);
17166  return;
17167  }
17168  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17169  {
17170  break; // OK found truncate element & no flashing LC in front
17171  }
17172  }
17173 
17174  for(unsigned int b = 0; b < PrefDirSize(); b++)
17175  {
17176  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17177  {
17178  if(PrefDirVector.at(b).TrackType == Bridge)
17179  {
17180  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17181  ReturnFlag = InRouteFalse;
17182  Utilities->CallLogPop(338);
17183  return;
17184  }
17185  if(b == 1)
17186  {
17187  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17188  ReturnFlag = InRouteFalse;
17189  Utilities->CallLogPop(339);
17190  return;
17191  }
17192  if(b > 0)
17193  {
17194  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17195  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17196  {
17197  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17198  {
17199  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17200  ReturnFlag = InRouteFalse;
17201  Utilities->CallLogPop(340);
17202  return;
17203  }
17204  }
17205  else
17206  {
17207  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17208  {
17209  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17210  ReturnFlag = InRouteFalse;
17211  Utilities->CallLogPop(341);
17212  return;
17213  }
17214  }
17215  }
17216  int RouteNumber;
17218 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17219 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17220 
17221 // check if part of this route already locked & disallow if so
17222  if(!(AllRoutes->LockedRouteVector.empty()))
17223  {
17225  {
17226  if(LRVIT->RouteNumber == RouteNumber)
17227  {
17228  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17229  ReturnFlag = InRouteFalse;
17230  Utilities->CallLogPop(749);
17231  return;
17232  }
17233  }
17234  }
17235  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17236  // RouteLockingRequired only checks for trains approaching
17237  {
17240  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17241  L"Warning!", MB_YESNO | MB_ICONWARNING);
17242  TrainController->BaseTime = TDateTime::CurrentDateTime();
17244  if(button == IDNO)
17245  {
17246  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17247  Utilities->CallLogPop(342);
17248  return;
17249  }
17250  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17251  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17252  TAllRoutes::TLockedRouteClass LockedRoute;
17253  bool ExistingLockedRouteModified = false;
17254  LockedRoute.RouteNumber = RouteNumber;
17255  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17256  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17257  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17258  LockedRoute.LockStartTime = TrainController->TTClockTime;
17259 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17260 // to use the new TruncateTrackVectorPosition & LockStartTime
17261  if(!AllRoutes->LockedRouteVector.empty())
17262  {
17263  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17264  LRVIT++)
17265  {
17266  if(LRVIT->RouteNumber == RouteNumber)
17267  {
17268  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17269  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17270  ExistingLockedRouteModified = true;
17271  }
17272  }
17273  }
17274  if(!ExistingLockedRouteModified)
17275  {
17276  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17277  }
17278  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17279  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17280  {
17281  // return all signals to red in route section to be truncated
17282  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17283  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17284  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17285  {
17286  TrackElement.Attribute = 0;
17287  Track->PlotSignal(2, TrackElement, Display);
17288  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17289  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17290  }
17291  }
17292 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17293  ReturnFlag = InRouteTrue;
17294  }
17295  else
17296  {
17297  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17298  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17299  {
17300  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17301  ReturnFlag = InRouteTrue;
17302  }
17303  }
17304  AllRoutes->CheckMapAndRoutes(5); // test
17305  Utilities->CallLogPop(343);
17306  return;
17307  }
17308  }
17309  ReturnFlag = NotInRoute;
17310  Utilities->CallLogPop(344);
17311 }
17312 
17313 // ---------------------------------------------------------------------------
17315 /*
17316  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17317  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17318  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17319  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17320  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17321  the route colours.
17322 */
17323 {
17324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17325  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17327  int RouteNumber;
17328  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17329  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17330 
17331  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17332  {
17333  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17334  {
17335  if(PrefDirVector.at(x).TrackType == SignalPost)
17336  {
17337  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17338  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17339  }
17340  }
17341  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17342 // already set all signals to red in route so start at start of route for further rearwards signal setting
17343  }
17344  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17345  {
17346  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17347  }
17348  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17349  AllRoutes->CheckMapAndRoutes(9); // test
17350  TrainController->BaseTime = TDateTime::CurrentDateTime();
17352  Utilities->CallLogPop(345);
17353  return;
17354 }
17355 
17356 // ---------------------------------------------------------------------------
17357 
17358 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17359 /*
17360  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17361 */
17362 {
17363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17364  AnsiString((short)PrefDirRoute));
17365  if(SearchVector.empty())
17366  {
17367  Utilities->CallLogPop(1149);
17368  return;
17369  }
17370  for(unsigned int b = 0; b < SearchVector.size(); b++)
17371  {
17374  PrefDirRoute);
17375  }
17376  Utilities->CallLogPop(346);
17377 }
17378 
17379 // ---------------------------------------------------------------------------
17380 
17381 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17382 /*
17383  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17384  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17385  TOneRoute.
17386 */
17387 {
17388  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17389  AnsiString((short)PrefDirRoute));
17390  RouteFlash.RouteFlashVector.clear();
17391  TRouteFlashElement RouteFlashElement;
17392 
17393  for(unsigned int b = 0; b < SearchVector.size(); b++)
17394  {
17395  int H = GetFixedSearchElementAt(11, b).HLoc;
17396  int V = GetFixedSearchElementAt(12, b).VLoc;
17398  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17399  RouteFlashElement.HLoc = H;
17400  RouteFlashElement.VLoc = V;
17402  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17403  }
17404  Utilities->CallLogPop(348);
17405 }
17406 
17407 // ---------------------------------------------------------------------------
17408 
17409 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17410 {
17411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17412  if(!PrefDirVector.empty())
17413  {
17414  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17415  {
17416  int H = PrefDirPtr->HLoc;
17417  int V = PrefDirPtr->VLoc;
17418  // check for any LCs that are closed to trains & set the flash values and store in the vector
17419  if(Track->IsLCAtHV(39, H, V))
17420  {
17421  if(Track->IsLCBarrierUpAtHV(0, H, V))
17422  {
17423  Track->LCChangeFlag = true;
17424  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17425  CLC.HLoc = H;
17426  CLC.VLoc = V;
17428  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17431  if(PrefDirRoute)
17432  {
17433  CLC.TypeOfRoute = 1;
17434  }
17435  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17436  Track->ChangingLCVector.push_back(CLC);
17437  }
17438  }
17439  }
17440  }
17441  Utilities->CallLogPop(1948);
17442 }
17443 
17444 // ---------------------------------------------------------------------------
17445 
17447 /*
17448  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17449  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17450  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17451  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17452 */
17453 {
17454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17455  if(!OverlayPlotted)
17456  {
17457  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17458  {
17459  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17460  {
17461  continue;
17462  }
17463  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17464  Display->Update();
17465  }
17466  OverlayPlotted = true;
17467  }
17468  Utilities->CallLogPop(349);
17469 }
17470 
17471 // ---------------------------------------------------------------------------
17472 
17474 /*
17475  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17476  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17477  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17478  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17479 */
17480 {
17481  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17482  if(OverlayPlotted)
17483  {
17484  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17485  {
17486  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17487  {
17488  continue;
17489  }
17490  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17491  Display->Update();
17492  }
17493  OverlayPlotted = false;
17494  }
17495  Utilities->CallLogPop(350);
17496 }
17497 
17498 // ---------------------------------------------------------------------------
17499 
17500 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17501 {
17502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17503  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17504  {
17505  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17506  }
17507  Utilities->CallLogPop(120);
17508  return(AllRoutesVector.at(At));
17509 }
17510 
17511 // ---------------------------------------------------------------------------
17512 // ---------------------------------------------------------------------------
17513 
17515 {
17516  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17517  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17518  {
17519  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17520  }
17521  Utilities->CallLogPop(121);
17522  return(AllRoutesVector.at(At));
17523 }
17524 
17525 // ---------------------------------------------------------------------------
17526 
17527 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17528 /*
17529  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17530 */
17531 {
17532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17533  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17534  {
17535  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17536  }
17537  Utilities->CallLogPop(351);
17538 }
17539 
17540 // ---------------------------------------------------------------------------
17541 
17542 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17543 {
17544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17545  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17546  {
17547  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17548  }
17549  Utilities->CallLogPop(1706);
17550 }
17551 
17552 // ---------------------------------------------------------------------------
17553 
17554 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17555 /*
17556  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17557  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17558  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17559  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17560  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17561  length (train length).
17562 */
17563 {
17564  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17565  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17566  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17567  {
17568  TTruncateReturnType ReturnFlag;
17569  RouteTruncateFlag = true;
17570 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17571  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17572  RouteTruncateFlag = false;
17573  if(ReturnFlag == NotInRoute)
17574  {
17575  continue;
17576  }
17577  else if(ReturnFlag == InRouteTrue)
17578  {
17579  Utilities->CallLogPop(352);
17580  return(true);
17581  }
17582  else if(ReturnFlag == InRouteFalse)
17583  {
17584  Utilities->CallLogPop(353);
17585  return(false);
17586  }
17587  }
17588  Utilities->CallLogPop(354);
17589  return(false);
17590 }
17591 
17592 // ---------------------------------------------------------------------------
17593 
17594 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17595 /*
17596  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17597  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17598 */
17599 {
17600  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17601  AnsiString(LinkPos));
17602  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17603  {
17604  Utilities->CallLogPop(355);
17605  return(false);
17606  }
17607  THVPair Route2MultiMapKeyPair;
17608 
17609  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17610  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17611  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17612  TRoute2MultiMapIterator Route2MultiMapIterator;
17613 
17614  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17615  {
17616  Utilities->CallLogPop(356);
17617  return(false);
17618  }
17619  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17620  {
17621  Utilities->CallLogPop(1422);
17622  return(true);
17623  }
17624  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17625  {
17626  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17627 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17628 // realised after writing this that can't be points as would have been covered above, but leave anyway
17629  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17630  Route2MultiMapIterator->second.second);
17631  EntryLinkPos = PrefDirElement1.ELinkPos;
17632  ExitLinkPos = PrefDirElement1.XLinkPos;
17633  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17634  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17635  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17636  {
17637  Utilities->CallLogPop(357);
17638  return(true);
17639  }
17640  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17641  {
17642  Utilities->CallLogPop(358);
17643  return(true);
17644  }
17645  }
17646  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17647  {
17648  Utilities->CallLogPop(1423);
17649  return(true);
17650  }
17651  Utilities->CallLogPop(363);
17652  return(false); // none found
17653 }
17654 
17655 // ---------------------------------------------------------------------------
17656 
17657 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17658  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17659 /*
17660  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17661  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17662  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17663  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17664  for replotting of AutoSigsRoutes.
17665 */
17666 {
17667  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17668  AnsiString(LinkPos));
17669  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17670  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17671  if(TrackVectorPosition == -1)
17672  {
17673  Utilities->CallLogPop(364);
17674  return(NoRoute); // allows for continuation entries & exits
17675  }
17676  THVPair Route2MultiMapKeyPair;
17677 
17678  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17679  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17680  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17681  TRoute2MultiMapIterator Route2MultiMapIterator;
17682 
17683  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17684  {
17685  Utilities->CallLogPop(365);
17686  return(NoRoute); // none found
17687  }
17688  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17689  {
17690  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17691 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17692  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17693  Route2MultiMapIterator->second.second);
17694  EntryLinkPos = PrefDirElement1.ELinkPos;
17695  ExitLinkPos = PrefDirElement1.XLinkPos;
17696  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17697  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17698  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17699  {
17700  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17701  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17702  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17703  {
17704  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17705  }
17706  if(PrefDirElement1.AutoSignals)
17707  {
17708  Utilities->CallLogPop(366);
17709  return(AutoSigsRoute);
17710  }
17711  else
17712  {
17713  Utilities->CallLogPop(367);
17714  return(NotAutoSigsRoute);
17715  }
17716  }
17717  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17718  {
17719  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17720  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17721  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17722  {
17723  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17724  }
17725  if(PrefDirElement1.AutoSignals)
17726  {
17727  Utilities->CallLogPop(368);
17728  return(AutoSigsRoute);
17729  }
17730  else
17731  {
17732  Utilities->CallLogPop(369);
17733  return(NotAutoSigsRoute);
17734  }
17735  }
17736  }
17737  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17738  {
17739  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17740  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17741 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17742  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17743  EntryLinkPos = PrefDirElement2.ELinkPos;
17744  ExitLinkPos = PrefDirElement2.XLinkPos;
17745  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17746  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17747  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17748  {
17749  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17750  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17751  {
17752  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17753  }
17754  if(PrefDirElement2.AutoSignals)
17755  {
17756  Utilities->CallLogPop(370);
17757  return(AutoSigsRoute);
17758  }
17759  else
17760  {
17761  Utilities->CallLogPop(371);
17762  return(NotAutoSigsRoute);
17763  }
17764  }
17765  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17766  {
17767  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17768  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17769  {
17770  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17771  }
17772  if(PrefDirElement2.AutoSignals)
17773  {
17774  Utilities->CallLogPop(372);
17775  return(AutoSigsRoute);
17776  }
17777  else
17778  {
17779  Utilities->CallLogPop(373);
17780  return(NotAutoSigsRoute);
17781  }
17782  }
17783  ItPair.second--; // the second iterator points one past the last matching value
17784  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17785  EntryLinkPos = PrefDirElement3.ELinkPos;
17786  ExitLinkPos = PrefDirElement3.XLinkPos;
17787  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17788  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17789  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17790  {
17791  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17792  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17793  {
17794  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17795  }
17796  if(PrefDirElement3.AutoSignals)
17797  {
17798  Utilities->CallLogPop(374);
17799  return(AutoSigsRoute);
17800  }
17801  else
17802  {
17803  Utilities->CallLogPop(375);
17804  return(NotAutoSigsRoute);
17805  }
17806  }
17807  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17808  {
17809  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17810  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17811  {
17812  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17813  }
17814  if(PrefDirElement3.AutoSignals)
17815  {
17816  Utilities->CallLogPop(376);
17817  return(AutoSigsRoute);
17818  }
17819  else
17820  {
17821  Utilities->CallLogPop(377);
17822  return(NotAutoSigsRoute);
17823  }
17824  }
17825  }
17826  Utilities->CallLogPop(378);
17827  return(NoRoute); // none found
17828 }
17829 
17830 // ---------------------------------------------------------------------------
17831 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17832 /*
17833  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
17834  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
17835 */
17836 {
17837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
17838  AnsiString(LinkPos));
17839  if(TrackVectorPosition == -1)
17840  {
17841  RouteNumber = -1;
17842  Utilities->CallLogPop(379);
17843  return(NoRoute); // allows for continuation & buffer entries & exits
17844  }
17845  THVPair Route2MultiMapKeyPair;
17846 
17847  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
17848  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
17849  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17850  TRoute2MultiMapIterator Route2MultiMapIterator;
17851 
17852  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17853  {
17854  RouteNumber = -1;
17855  Utilities->CallLogPop(380);
17856  return(NoRoute); // none found
17857  }
17858  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17859  {
17860  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17861 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17862  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
17863  Route2MultiMapIterator->second.second);
17864  EntryLinkPos = PrefDirElement1.ELinkPos;
17865  ExitLinkPos = PrefDirElement1.XLinkPos;
17866  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17867  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17868  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
17869  {
17870  RouteNumber = Route2MultiMapIterator->second.first;
17871  if(PrefDirElement1.AutoSignals)
17872  {
17873  Utilities->CallLogPop(381);
17874  return(AutoSigsRoute);
17875  }
17876  else
17877  {
17878  Utilities->CallLogPop(382);
17879  return(NotAutoSigsRoute);
17880  }
17881  }
17882  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
17883  {
17884  RouteNumber = Route2MultiMapIterator->second.first;
17885  if(PrefDirElement1.AutoSignals)
17886  {
17887  Utilities->CallLogPop(383);
17888  return(AutoSigsRoute);
17889  }
17890  else
17891  {
17892  Utilities->CallLogPop(384);
17893  return(NotAutoSigsRoute);
17894  }
17895  }
17896  }
17897  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17898  {
17899  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17900  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17901 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17902  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
17903  EntryLinkPos = PrefDirElement2.ELinkPos;
17904  ExitLinkPos = PrefDirElement2.XLinkPos;
17905  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17906  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17907  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
17908  {
17909  RouteNumber = ItPair.first->second.first;
17910  if(PrefDirElement2.AutoSignals)
17911  {
17912  Utilities->CallLogPop(385);
17913  return(AutoSigsRoute);
17914  }
17915  else
17916  {
17917  Utilities->CallLogPop(386);
17918  return(NotAutoSigsRoute);
17919  }
17920  }
17921  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
17922  {
17923  RouteNumber = ItPair.first->second.first;
17924  if(PrefDirElement2.AutoSignals)
17925  {
17926  Utilities->CallLogPop(387);
17927  return(AutoSigsRoute);
17928  }
17929  else
17930  {
17931  Utilities->CallLogPop(388);
17932  return(NotAutoSigsRoute);
17933  }
17934  }
17935  ItPair.second--; // the second iterator points one past the last matching value
17936  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
17937  EntryLinkPos = PrefDirElement3.ELinkPos;
17938  ExitLinkPos = PrefDirElement3.XLinkPos;
17939  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17940  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17941  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
17942  {
17943  RouteNumber = ItPair.second->second.first;
17944  if(PrefDirElement3.AutoSignals)
17945  {
17946  Utilities->CallLogPop(389);
17947  return(AutoSigsRoute);
17948  }
17949  else
17950  {
17951  Utilities->CallLogPop(390);
17952  return(NotAutoSigsRoute);
17953  }
17954  }
17955  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
17956  {
17957  RouteNumber = ItPair.second->second.first;
17958  if(PrefDirElement3.AutoSignals)
17959  {
17960  Utilities->CallLogPop(391);
17961  return(AutoSigsRoute);
17962  }
17963  else
17964  {
17965  Utilities->CallLogPop(392);
17966  return(NotAutoSigsRoute);
17967  }
17968  }
17969  }
17970  RouteNumber = -1;
17971  Utilities->CallLogPop(393);
17972  return(NoRoute); // none found
17973 }
17974 
17975 // ---------------------------------------------------------------------------
17976 
17977 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
17978 /*
17979  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
17980  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
17981  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
17982  and Route2MultiMap.
17983 */
17984 {
17985  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
17986  TOneRoute EmptyRoute;
17987 
17988  EmptyRoute.RouteID = NextRouteID;
17989  NextRouteID++;
17990 
17991  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17992  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17993  {
17994  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
17995  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
17996  }
17997  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
17998  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
17999 
18000  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
18001  Utilities->CallLogPop(394);
18002 }
18003 
18004 // ---------------------------------------------------------------------------
18005 
18007 /*
18008  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
18009  that is already in Route is used.
18010 */
18011 {
18012  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
18013  TOneRoute EmptyRoute;
18014 
18015  EmptyRoute.RouteID = Route->RouteID;
18016 
18017  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18018  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18019  {
18020  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
18021  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
18022  }
18023  Utilities->CallLogPop(1579);
18024 }
18025 
18026 // ---------------------------------------------------------------------------
18027 
18028 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
18029 /*
18030  When attaching a new route section to an existing route, it is sometimes necessary to erase the
18031  original route and create a new composite route. This function Erases all elements in the route
18032  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
18033  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
18034  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
18035  that are greater than the route number that is removed. The LockedRouteVector as also searched
18036  and if any relate to the route that has been cleared they are erased too, but the fact that one
18037  has been found is recorded so that it can be re-established later.
18038 */
18039 {
18040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
18041  THVPair Route2MultiMapKeyPair;
18042  TRoute2MultiMapEntry Route2MultiMapEntry;
18043  TRoute2MultiMapIterator Route2MultiMapIterator;
18044 
18045 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
18046 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
18047 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
18048 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
18049 // If so the locked route is removed from the locked vector and is lost.
18050  LockedRouteTruncateTrackVectorPosition = 0;
18051  LockedRouteLastTrackVectorPosition = 0;
18052  LockedRouteLastXLinkPos = 0;
18053  LockedRouteLockStartTime = TDateTime(0);
18054  if(!LockedRouteVector.empty())
18055  {
18056  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18057  {
18058  if(LRVIT->RouteNumber == RouteNumber)
18059  {
18060  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
18061  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
18062  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
18063  LockedRouteLockStartTime = LRVIT->LockStartTime;
18064  LockedRouteFoundDuringRouteBuilding = true;
18065  LockedRouteVector.erase(LRVIT);
18066  }
18067  }
18068  }
18069  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
18070  {
18071  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
18072  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
18073  }
18074  Utilities->CallLogPop(395);
18075 }
18076 
18077 // ---------------------------------------------------------------------------
18078 
18080  TRoute2MultiMapIterator &Route2MultiMapIterator)
18081 /*
18082  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
18083  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
18084  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
18085  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
18086  are given for failure.
18087 */
18088 {
18089  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18090  AnsiString(VLoc) + "," + AnsiString(ELink));
18091  TRouteElementPair ReturnPair;
18092 
18093  ReturnPair.first = -1;
18094  ReturnPair.second = 0;
18095  THVPair Route2MultiMapKeyPair;
18096 
18097  Route2MultiMapKeyPair.first = HLoc;
18098  Route2MultiMapKeyPair.second = VLoc;
18099  TRoute2MultiMapEntry Route2MultiMapEntry;
18100 
18101  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18102  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18103 
18104  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18105  Route2MultiMapIterator = ItPair.first;
18106 
18107  if(ItPair.first == ItPair.second)
18108  {
18109  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
18110  }
18111  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
18112  {
18113  ReturnPair.first = ItPair.first->second.first;
18114  ReturnPair.second = ItPair.first->second.second;
18115  Route2MultiMapIterator = ItPair.first;
18116  Utilities->CallLogPop(396);
18117  return(ReturnPair);
18118  }
18119  ItPair.first++;
18120  if(ItPair.first == ItPair.second)
18121  {
18122  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
18123  }
18124  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18125  {
18126  ReturnPair.first = ItPair.first->second.first;
18127  ReturnPair.second = ItPair.first->second.second;
18128  Route2MultiMapIterator = ItPair.first;
18129  Utilities->CallLogPop(397);
18130  return(ReturnPair);
18131  }
18132  Utilities->CallLogPop(398);
18133  return(ReturnPair);
18134 }
18135 
18136 // ---------------------------------------------------------------------------
18137 
18138 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18139 /*
18140  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18141  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18142  RouteNumber (route position in AllRoutes vector is returned as a reference.
18143  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18144  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18145 */
18146 {
18147  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18148  AnsiString(VLoc) + "," + AnsiString(ELink));
18149  THVPair Route2MultiMapKeyPair;
18150 
18151  Route2MultiMapKeyPair.first = HLoc;
18152  Route2MultiMapKeyPair.second = VLoc;
18153  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18154 
18155  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18156 
18157  if(ItPair.first == ItPair.second)
18158  {
18159  RouteNumber = -1;
18160  Utilities->CallLogPop(2032);
18161  return(false);
18162  }
18163  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18164  {
18165  RouteNumber = ItPair.first->second.first;
18166  Utilities->CallLogPop(2033);
18167  return(true);
18168  }
18169  ItPair.first++;
18170 
18171  if(ItPair.first == ItPair.second)
18172  {
18173  RouteNumber = -1;
18174  Utilities->CallLogPop(2034);
18175  return(false);
18176  }
18177  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18178  {
18179  RouteNumber = ItPair.first->second.first;
18180  Utilities->CallLogPop(2035);
18181  return(true);
18182  }
18183  RouteNumber = -1;
18184  Utilities->CallLogPop(2036);
18185  return(false);
18186 }
18187 
18188 // ---------------------------------------------------------------------------
18189 
18190 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18191 /*
18192  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18193  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18194  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18195  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18196  Called by TAllRoutes::AddRouteElement.
18197 */
18198 {
18199  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18200  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18201  THVPair Route2MultiMapKeyPair;
18202 
18203  Route2MultiMapKeyPair.first = HLoc;
18204  Route2MultiMapKeyPair.second = VLoc;
18205  TRoute2MultiMapEntry Route2MultiMapEntry;
18206 
18207  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18208  TRouteElementPair RouteElementPair;
18209 
18210  RouteElementPair.first = RouteNumber;
18211  RouteElementPair.second = RouteElementNumber;
18212  Route2MultiMapEntry.second = RouteElementPair;
18213 
18214  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18215  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18216  {
18217  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18218  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18219  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18220  {
18221  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18222  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18223  {
18224  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18225  }
18226  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18227  }
18228  else
18229  // same ELink so have an error
18230  {
18231  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18232  }
18233  }
18234  else
18235  {
18236  Route2MultiMap.insert(Route2MultiMapEntry);
18237  }
18238 // element at H&V not found in map so insert it
18239  Utilities->CallLogPop(399);
18240 }
18241 
18242 // ---------------------------------------------------------------------------
18243 
18245 /*
18246  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18247  and the second in the reference SecondPair. If there's only one then it's the function return
18248 */
18249 {
18250  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18251  AnsiString(VLoc));
18253 
18254  TempPair.first = -1;
18255  TempPair.second = 0;
18256  SecondPair = TempPair;
18257  TRoute2MultiMapIterator Route2MultiMapIterator;
18258  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18259  THVPair Route2MultiMapKeyPair;
18260 
18261  Route2MultiMapKeyPair.first = HLoc;
18262  Route2MultiMapKeyPair.second = VLoc;
18263  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18264  {
18265  Utilities->CallLogPop(400);
18266  return(TempPair);
18267  }
18268  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18269  {
18270  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18271  Utilities->CallLogPop(401);
18272  return(Route2MultiMapIterator->second);
18273  }
18274  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18275  {
18276  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18277  TempPair = ItRange.first->second;
18278  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
18279  Utilities->CallLogPop(402);
18280  return(TempPair);
18281  }
18282  Utilities->CallLogPop(403);
18283  return(TempPair);
18284 }
18285 
18286 // ---------------------------------------------------------------------------
18287 
18288 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
18289 /*
18290  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
18291  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
18292 */
18293 {
18294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
18295  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
18296  {
18297  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
18298  {
18299  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
18300  TAllRoutes::TRouteElementPair SecondPair;
18301  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
18302  if(RouteElementPair.first == -1)
18303  // failed to find element in multimap
18304  {
18305  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
18306  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
18307  }
18308  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
18309  // neither pair has expected route number
18310  {
18311  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18312  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
18313  (AnsiString)Caller);
18314  }
18315  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
18316  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
18317  {
18318  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18319  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
18320  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
18321  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
18322  }
18323  }
18324  }
18325  unsigned int SizeVal = 0;
18326 
18327 // check map and sum of route sizes match
18328  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18329  {
18330  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
18331  }
18332  if(SizeVal != Route2MultiMap.size())
18333  {
18334  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
18335  (AnsiString)Caller);
18336  }
18337  Utilities->CallLogPop(404);
18338  return;
18339 }
18340 
18341 // ---------------------------------------------------------------------------
18342 
18343 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
18344 /*
18345  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
18346  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
18347  exceed that for the erased route. Where this is so the RouteNumber is decremented.
18348 */
18349 {
18350  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
18351  if(!Route2MultiMap.empty())
18352  {
18353  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18354  {
18355  if(Route2MultiMapIterator->second.first > RouteNumber)
18356  {
18357  Route2MultiMapIterator->second.first--;
18358  }
18359  }
18360  }
18361  Utilities->CallLogPop(405);
18362 }
18363 
18364 // ---------------------------------------------------------------------------
18365 
18366 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
18367 /*
18368  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
18369  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18370  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18371 */
18372 {
18373  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18374  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18375  if(!Route2MultiMap.empty())
18376  {
18377  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18378  {
18379  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18380  {
18381  Route2MultiMapIterator->second.second--;
18382  }
18383  }
18384  }
18385  Utilities->CallLogPop(406);
18386 }
18387 
18388 // ---------------------------------------------------------------------------
18389 
18390 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18391 /*
18392  Erases the route element from Route2MultiMap and from the PrefDirVector.
18393  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18394  decremented if they are greater than the element number removed, and if the entire route is removed
18395  then the route numbers are also decremented in the map for route numbers that are greater than the route
18396  number that is removed.
18397 */
18398 {
18399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18400  AnsiString(ELink));
18401  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18402  TRoute2MultiMapIterator Route2MultiMapIterator;
18403 
18404  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18405  if(RequiredRoutePair.first == -1)
18406  {
18407  throw Exception("Failed to find route element in RemoveRouteElement");
18408  }
18409  Route2MultiMap.erase(Route2MultiMapIterator);
18410  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18411 
18412 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18413  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18414 
18415  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18416  {
18417  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18418  }
18419 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18420 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18421 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18422 // to check if a route element is present, and the element has already been removed from the map - see above.
18423 
18424 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18425 /*
18426  int LockedVectorNumber = -1;
18427  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18428  {
18429  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18430  }
18431 */
18432 
18433 // erase element from route
18434  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18435  RequiredRoutePair.second)));
18436 // CheckMapAndRoutes();//test - drop - tested below
18437 
18438 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18439 // be so as continuation exit is at the end of the route, and truncation is from the end
18441  {
18443  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18444  AutoSigVectorIT--)
18445  {
18446  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18447  {
18448  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18449  }
18450  }
18451  }
18452 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18453 // and adjust all the corresponding route numbers
18454  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18455  {
18456  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18457  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18458  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18459 
18460 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18461  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18462  it is erased then - see TInterface::ApproachLocking
18463 
18464  if(LockedVectorNumber > -1)
18465  {
18466  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18467  }
18468 */
18469  // decrement route numbers in the locked route vector whether or not this route is a locked route
18470  if(!LockedRouteVector.empty())
18471  {
18472  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18473  {
18474  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18475  {
18476  LRVIT->RouteNumber--;
18477  }
18478  }
18479  }
18481  {
18483  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18484  AutoSigVectorIT--)
18485  {
18486  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18487  {
18488  AutoSigVectorIT->RouteNumber--;
18489  }
18490  }
18491  }
18492  }
18493  CheckMapAndRoutes(7); // test
18494  Utilities->CallLogPop(407);
18495 }
18496 
18497 // ---------------------------------------------------------------------------
18498 
18499 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18500 /*
18501  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18502  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18503  since that catches all route elements wherever created
18504 */
18505 {
18506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18507  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18508  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18509  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18510  Utilities->CallLogPop(408);
18511 }
18512 
18513 // ---------------------------------------------------------------------------
18514 
18515 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18516 /*
18517  Enter with signal at TrackVectorElement already set to red by the passing train.
18518  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18519  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18520  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18521  case the function sets no further signals.
18522 */
18523 {
18524  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18525  "," + AnsiString(XLinkPos));
18526  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18527  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18528 
18529  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18530  if(RouteElementPair.first == -1)
18531  {
18532  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18533  }
18534  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18535 
18536  RequiredPair = RouteElementPair;
18537  if(RouteElement.XLinkPos != XLinkPos)
18538  {
18539  if(SecondPair.first != -1)
18540  {
18541  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18542  RequiredPair = SecondPair;
18543  if(RouteElement.XLinkPos != XLinkPos)
18544  {
18545  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18546  }
18547  }
18548  else
18549  {
18550  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18551  }
18552  }
18553 // new function
18554  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18555  Utilities->CallLogPop(409);
18556 }
18557 
18558 // ---------------------------------------------------------------------------
18559 
18560 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18561 /*
18562  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18563  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18564  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18565  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18566  to 2 for successive calls.
18567  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18568  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18569  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18570  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18571 */
18572 {
18573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18574  AnsiString(AccessNumber));
18575  TPrefDirElement RouteElement;
18576  int Attribute = AccessNumber + 1;
18577 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18578  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18579 
18580  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18581  {
18582  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18583  }
18584  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18585  {
18586  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18587  }
18588  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18589  x).XLinkPos] != End)
18590  {
18591  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18592  }
18593 // new function
18594  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18595  Utilities->CallLogPop(410);
18596 }
18597 
18598 // ---------------------------------------------------------------------------
18599 
18600 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18601 /*
18602  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18603  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18604  or (b) in a linked rear route, in which case the function sets no further signals.
18605 
18606  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18607  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18608  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18609  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18610  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18611  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18612  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18613  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18614  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18615  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18616  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18617  found behind the train.
18618 
18619  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18620  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18621  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18622  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18623  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18624  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18625  a route.
18626 
18627  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18628  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18629  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
18630  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
18631  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18632  reference. If no train is found before the beginning of the route is reached the function returns true
18633 
18634 */
18635 {
18636  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18637  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18638  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18639  int RearwardLinkedRouteNumber;
18640 
18641  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18642  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18643  // signal value in the route for use in further linked routes
18644  {
18645  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18646  {
18647  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18648  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18649  {
18650  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18651  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18652  {
18653  break;
18654  }
18655  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18656  // flash LCs on those routes
18657  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18658  }
18659  }
18660  }
18661  else
18662  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18663  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18664  {
18665  int TrainID, TrainPosition, BehindTrainPosition;
18666  bool FoundTrain = false, BehindTrain = false;
18667  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18668  {
18669  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18670  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18671  TrainID = TrackElement.TrainIDOnElement;
18672  if(TrackElement.TrackType == Bridge)
18673  {
18674  if(PrefDirElement.XLinkPos < 2)
18675  {
18676  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18677  }
18678  else
18679  {
18680  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18681  }
18682  }
18683  if(TrainID == -1)
18684  {
18685  continue;
18686  }
18687  else
18688  {
18689  FoundTrain = true;
18690  TrainPosition = x;
18691  break;
18692  }
18693  }
18694  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18695  {
18696  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18697  {
18698  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18699  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18700  // need the element behind the rearmost train.
18701  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18702  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18703  TrainID = TrackElement.TrainIDOnElement;
18704  if(TrackElement.TrackType == Bridge)
18705  {
18706  if(PrefDirElement.XLinkPos < 2)
18707  {
18708  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18709  }
18710  else
18711  {
18712  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18713  }
18714  }
18715  if(TrainID != -1)
18716  {
18717  continue; // still on train
18718  }
18719  else
18720  {
18721  BehindTrain = true;
18722  BehindTrainPosition = x;
18723  break;
18724  }
18725  }
18726  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18727  // so on for as many trains as there are on the single route
18728  {
18729  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18730  // first signal behind train to be red
18731  }
18732  }
18733  }
18734  Utilities->CallLogPop(411);
18735 }
18736 
18737 // ---------------------------------------------------------------------------
18738 
18739 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18740 {
18741 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18742  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18743  first signal is red, then OK
18744 */
18745  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18746  AnsiString(RouteTruncatePosition));
18747  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18748  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18749  TPrefDirElement PrefDirElement, FirstElement;
18750  TTrackElement TrackElement;
18751  bool ExamineRoute = true;
18752 
18753  while(ExamineRoute)
18754  {
18755  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18756  {
18757  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18758  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18759  TrainID = TrackElement.TrainIDOnElement;
18760  if(TrackElement.TrackType == Bridge)
18761  {
18762  if(PrefDirElement.XLinkPos < 2)
18763  {
18764  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18765  }
18766  else
18767  {
18768  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18769  }
18770  }
18771  if(TrainID > -1)
18772  {
18773  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18774  {
18775  //any trains further back in route will be protected by the red signal behind the stopped train
18776  Utilities->CallLogPop(412);
18777  return(false);
18778  }
18779  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18780  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18781  //other way & can cancel the route
18782  {
18783  Utilities->CallLogPop(2203);
18784  return(false);
18785  }
18786  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18787  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18788  }
18789  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18790  {
18791  if(TrackElement.Attribute == 0)
18792  {
18793  Utilities->CallLogPop(413);
18794  return(false); // OK, red signal in front of a train
18795  }
18796  SignalCount++;
18797  if(SignalCount >= 3)
18798  {
18799  Utilities->CallLogPop(414);
18800  return(false);
18801  }
18802  }
18803  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18804  // ElinkPos because working back along PrefDir to beginning
18805  {
18806  Utilities->CallLogPop(415);
18807  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18808  }
18809  }
18810  //now look at linked rearwards routes
18811  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18812  StartPosition = CurrentRoute.PrefDirSize() - 1;
18813  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18814  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18815  {
18816  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18817  ExamineRoute = true;
18818  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18819  }
18820  else
18821  {
18822  // here check for a train on the element immediately before the first route element
18823  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18824  TrainID = PriorTrackElement.TrainIDOnElement;
18825  if(PriorTrackElement.TrackType == Bridge)
18826  {
18827  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18828  {
18829  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18830  }
18831  else
18832  {
18833  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
18834  }
18835  }
18836  if(TrainID > -1)
18837  {
18838  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
18839  {
18840  Utilities->CallLogPop(748);
18841  return(false);
18842  }
18843  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
18844  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
18845  //other way & can cancel the route
18846  {
18847  Utilities->CallLogPop(2204);
18848  return(false);
18849  }
18850  Utilities->CallLogPop(1962);
18851  return(true); //otherwise need to lock the route
18852  }
18853  ExamineRoute = false;
18854  }
18855  }
18856 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
18857 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
18858  Utilities->CallLogPop(416);
18859  return(false);
18860 }
18861 
18862 // ---------------------------------------------------------------------------
18863 
18864 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
18865  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
18866 {
18867  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
18868  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
18869  TPrefDirElement InternalPrefDirElement; // blank element
18870 
18871  PrefDirElement = InternalPrefDirElement;
18872  if(LockedRouteVector.empty())
18873  {
18874  Utilities->CallLogPop(417);
18875  return(false);
18876  }
18877 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
18878 // even if some elements have been removed from the front by a train
18879  bool InLockedRoute = false;
18880 
18881  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18882  {
18883  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
18884  {
18885  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
18886  // doesn't arise)
18887  InLockedRoute = true;
18888  break;
18889  }
18890  }
18891  if(!InLockedRoute)
18892  {
18893  Utilities->CallLogPop(418);
18894  return(false);
18895  }
18896  int RouteNumber, VectorCount = 0;
18897  TRouteType RouteType;
18898 
18899  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18900  {
18901  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
18902  if(RouteType == NoRoute)
18903  {
18904  continue;
18905  }
18906  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
18907  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
18908  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
18909  {
18910  throw Exception
18911  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
18912  }
18913  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
18914  {
18915  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
18916  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
18917  {
18918  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18919  {
18920  PrefDirElement = InternalPrefDirElement;
18921  LockedVectorNumber = VectorCount;
18922  Utilities->CallLogPop(419);
18923  return(true);
18924  }
18925  }
18926  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
18927  {
18928  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18929  {
18930  PrefDirElement = InternalPrefDirElement;
18931  LockedVectorNumber = VectorCount;
18932  Utilities->CallLogPop(420);
18933  return(true);
18934  }
18935  else
18936  {
18937  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
18938  }
18939  }
18940  }
18941  VectorCount++;
18942  }
18943  Utilities->CallLogPop(421);
18944  return(false);
18945 }
18946 
18947 // ---------------------------------------------------------------------------
18948 
18950 {
18951  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
18952  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18953  {
18954  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
18955  {
18956  Utilities->CallLogPop(963);
18957  return(x);
18958  }
18959  }
18960  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
18961 }
18962 
18963 // ---------------------------------------------------------------------------
18964 
18966 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
18967 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
18968 {
18969  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18970  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18971  {
18972  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
18973  {
18974  Utilities->CallLogPop(2039);
18975  return(true);
18976  }
18977  }
18978  Utilities->CallLogPop(2040);
18979  return(false);
18980 }
18981 
18982 // ---------------------------------------------------------------------------
18983 
18985 {
18986  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18987  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18988  {
18989  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
18990  {
18991  Utilities->CallLogPop(964);
18992  return(GetFixedRouteAt(159, x));
18993  }
18994  }
18995  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18996 }
18997 
18998 // ---------------------------------------------------------------------------
18999 
19001 {
19002  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
19003  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19004  {
19005  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
19006  {
19007  Utilities->CallLogPop(965);
19008  return(GetModifiableRouteAt(15, x));
19009  }
19010  }
19011  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19012 }
19013 
19014 // ---------------------------------------------------------------------------
19015 
19016 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
19017 {
19018  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
19019  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
19020  Utilities->SaveFileInt(OutFile, NextRouteID);
19021  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19022  {
19023  TOneRoute OneRoute = GetFixedRouteAt(165, x);
19024  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
19025  OneRoute.SavePrefDirVector(6, OutFile);
19026  }
19027  Utilities->CallLogPop(1442);
19028 }
19029 
19030 // ---------------------------------------------------------------------------
19031 
19032 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
19033 {
19034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
19035  int NumberOfRoutes;
19036 
19037  NumberOfRoutes = Utilities->LoadFileInt(InFile);
19038  NextRouteID = Utilities->LoadFileInt(InFile);
19039  for(int x = 0; x < NumberOfRoutes; x++)
19040  {
19041  TOneRoute OneRoute; // empty route
19042  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
19043  OneRoute.LoadPrefDir(2, InFile);
19045  {
19046  StoreOneRouteAfterSessionLoad(0, &OneRoute);
19047  }
19048  else
19049  {
19050  Utilities->CallLogPop(1443);
19051  return(false);
19052  }
19053  }
19054  Utilities->CallLogPop(1444);
19055  return(true);
19056 }
19057 
19058 // ---------------------------------------------------------------------------
19059 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
19060 {
19061  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
19062  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
19063 
19064  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
19065  {
19066  Utilities->CallLogPop(1445);
19067  return(false);
19068  }
19069  int NextID = Utilities->LoadFileInt(InFile);
19070 
19071  if((NextID < 0) || (NextID > 1000000))
19072  {
19073  Utilities->CallLogPop(1446);
19074  return(false);
19075  }
19076  for(int x = 0; x < NumberOfRoutes; x++)
19077  {
19078  int RouteID = Utilities->LoadFileInt(InFile);
19079  if((RouteID < 0) || (RouteID > 20000))
19080  {
19081  Utilities->CallLogPop(1447);
19082  return(false);
19083  }
19084  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
19085  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
19086  {
19087  Utilities->CallLogPop(1448);
19088  return(false);
19089  }
19090  }
19091  Utilities->CallLogPop(1449);
19092  return(true);
19093 }
19094 
19095 // ---------------------------------------------------------------------------
19096 
19097 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
19098 {
19099  // return true for a loop
19100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
19101  AnsiString(StartPosition));
19102  if(EndPosition == StartPosition)
19103  {
19104  Utilities->CallLogPop(1839);
19105  return(true); // shouldn't happen but treat as a loop if does
19106  }
19107 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
19108  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
19109  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
19110 
19111  while(TrackIsInARoute(15, TVPos, LkPos))
19112  {
19113  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
19114  int NewLkPos = -1;
19115  if(NewTVPos > -1)
19116  {
19117  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
19118  if(NewLkPos == -1)
19119  {
19120  Utilities->CallLogPop(1840);
19121  return(true); // shouldn't arise but treat as loop if does
19122  }
19123  }
19124  else // reached a buffer or continuation
19125  {
19126  Utilities->CallLogPop(1841);
19127  return(false);
19128  }
19129 //Error found by Xeon notified by email 13/10/20.
19130 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19131 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19132 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19133 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19134 //New check added for v2.6.0
19135 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19136 //as possible in case there are other unforeseen effects.
19137  int RouteNumber; //dummy, not used
19138  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19139  {
19140  Utilities->CallLogPop(2241);
19141  return(false);
19142  }
19143  //now make the connected element the current element, read across the TV number and determine the exit link
19144  TVPos = NewTVPos;
19145  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19146  {
19147  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19148  {
19149  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19150  {
19151  LkPos = 1;
19152  }
19153  else
19154  {
19155  LkPos = 3;
19156  }
19157  }
19158  else
19159  {
19160  LkPos = 0;
19161  }
19162  }
19163  else
19164  {
19165  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19166  }
19167  if(TVPos == StartPosition)
19168  {
19169  Utilities->CallLogPop(1842);
19170  return(true); // it is a loop
19171  }
19172  }
19173  Utilities->CallLogPop(1843);
19174  return(false); // reached end of route so not a loop
19175 }
19176 
19177 // ---------------------------------------------------------------------------
19178 
19179 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19180 /*
19181  Track geometry allows diagonals to cross without occupying the same track element, so when
19182  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19183  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19184  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19185  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19186  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19187  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19188  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19189  Each of these is examined in turn for each route element in the relevant position.
19190 
19191  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19192  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19193  that returns false in all cases (including elements & links not present) except train present.
19194 */
19195 {
19196  int TrainID; // not used in this function
19197 
19198  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19199  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19200  TPrefDirElement TempPrefDirElement;
19201  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19202 
19203  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19204  if(FirstPair.first > -1)
19205  {
19206  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19207  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19208  {
19209  Utilities->CallLogPop(310);
19210  return(true);
19211  }
19212  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19213  {
19214  Utilities->CallLogPop(311);
19215  return(true);
19216  }
19217  }
19218  if(SecondPair.first > -1)
19219  {
19220  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19221  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19222  {
19223  Utilities->CallLogPop(312);
19224  return(true);
19225  }
19226  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19227  {
19228  Utilities->CallLogPop(313);
19229  return(true);
19230  }
19231  }
19232  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19233  9, TrainID)))
19234  {
19235  Utilities->CallLogPop(1997);
19236  return(true);
19237  }
19238  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19239  if(FirstPair.first > -1)
19240  {
19241  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19242  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19243  {
19244  Utilities->CallLogPop(314);
19245  return(true);
19246  }
19247  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19248  {
19249  Utilities->CallLogPop(315);
19250  return(true);
19251  }
19252  }
19253  if(SecondPair.first > -1)
19254  {
19255  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19256  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19257  {
19258  Utilities->CallLogPop(316);
19259  return(true);
19260  }
19261  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19262  {
19263  Utilities->CallLogPop(317);
19264  return(true);
19265  }
19266  }
19267  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19268  9, TrainID)))
19269  {
19270  Utilities->CallLogPop(1998);
19271  return(true);
19272  }
19273  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19274  if(FirstPair.first > -1)
19275  {
19276  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
19277  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19278  {
19279  Utilities->CallLogPop(318);
19280  return(true);
19281  }
19282  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19283  {
19284  Utilities->CallLogPop(319);
19285  return(true);
19286  }
19287  }
19288  if(SecondPair.first > -1)
19289  {
19290  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
19291  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19292  {
19293  Utilities->CallLogPop(320);
19294  return(true);
19295  }
19296  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19297  {
19298  Utilities->CallLogPop(321);
19299  return(true);
19300  }
19301  }
19302  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
19303  7, TrainID)))
19304  {
19305  Utilities->CallLogPop(1999);
19306  return(true);
19307  }
19308  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
19309  if(FirstPair.first > -1)
19310  {
19311  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
19312  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19313  {
19314  Utilities->CallLogPop(322);
19315  return(true);
19316  }
19317  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19318  {
19319  Utilities->CallLogPop(323);
19320  return(true);
19321  }
19322  }
19323  if(SecondPair.first > -1)
19324  {
19325  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
19326  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19327  {
19328  Utilities->CallLogPop(324);
19329  return(true);
19330  }
19331  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19332  {
19333  Utilities->CallLogPop(325);
19334  return(true);
19335  }
19336  }
19337  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
19338  3, TrainID)))
19339  {
19340  Utilities->CallLogPop(2000);
19341  return(true);
19342  }
19343  Utilities->CallLogPop(326);
19344  return(false);
19345 }
19346 
19347 // ---------------------------------------------------------------------------
19348 
19349 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19350 /*
19351  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
19352  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19353  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19354  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19355  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19356  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19357  Each of these is examined in turn for each route element in the relevant position.
19358 */
19359 {
19360  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19361  "," + AnsiString(DiagonalLinkNumber));
19362  TPrefDirElement TempPrefDirElement;
19363  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19364 
19365  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
19366  if(FirstPair.first > -1)
19367  {
19368  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
19369  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19370  {
19371  Utilities->CallLogPop(2010);
19372  return(true);
19373  }
19374  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19375  {
19376  Utilities->CallLogPop(2011);
19377  return(true);
19378  }
19379  }
19380  if(SecondPair.first > -1)
19381  {
19382  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19383  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19384  {
19385  Utilities->CallLogPop(2012);
19386  return(true);
19387  }
19388  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19389  {
19390  Utilities->CallLogPop(2013);
19391  return(true);
19392  }
19393  }
19394  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19395  if(FirstPair.first > -1)
19396  {
19397  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19398  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19399  {
19400  Utilities->CallLogPop(2014);
19401  return(true);
19402  }
19403  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19404  {
19405  Utilities->CallLogPop(2015);
19406  return(true);
19407  }
19408  }
19409  if(SecondPair.first > -1)
19410  {
19411  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19412  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19413  {
19414  Utilities->CallLogPop(2016);
19415  return(true);
19416  }
19417  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19418  {
19419  Utilities->CallLogPop(2017);
19420  return(true);
19421  }
19422  }
19423  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19424  if(FirstPair.first > -1)
19425  {
19426  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19427  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19428  {
19429  Utilities->CallLogPop(2018);
19430  return(true);
19431  }
19432  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19433  {
19434  Utilities->CallLogPop(2019);
19435  return(true);
19436  }
19437  }
19438  if(SecondPair.first > -1)
19439  {
19440  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19441  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19442  {
19443  Utilities->CallLogPop(2020);
19444  return(true);
19445  }
19446  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19447  {
19448  Utilities->CallLogPop(2021);
19449  return(true);
19450  }
19451  }
19452  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19453  if(FirstPair.first > -1)
19454  {
19455  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19456  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19457  {
19458  Utilities->CallLogPop(2022);
19459  return(true);
19460  }
19461  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19462  {
19463  Utilities->CallLogPop(2023);
19464  return(true);
19465  }
19466  }
19467  if(SecondPair.first > -1)
19468  {
19469  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19470  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19471  {
19472  Utilities->CallLogPop(2024);
19473  return(true);
19474  }
19475  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19476  {
19477  Utilities->CallLogPop(2025);
19478  return(true);
19479  }
19480  }
19481  Utilities->CallLogPop(2026);
19482  return(false);
19483 }
19484 
19485 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8437
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:691
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17594
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1284
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:931
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11365
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:677
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:744
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:627
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:579
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11338
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:432
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:566
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:889
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5481
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12884
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:786
TFixedTrackPiece
Definition: TrackUnit.h:82
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1690
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:790
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:922
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18190
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:91
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:805
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:923
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9926
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:807
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18600
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:934
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1338
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:782
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:595
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:716
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13305
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:773
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:634
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:797
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:430
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12924
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:693
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3686
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:714
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:895
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:780
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:281
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7181
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1607
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17106
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:698
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1670
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:711
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5633
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7082
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5660
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1492
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:586
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1631
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:66
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:840
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:861
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1928
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10260
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:616
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:16856
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:626
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:920
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:19349
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:432
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1661
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:607
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2824
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:551
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5813
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:742
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:686
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:150
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8100
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1502
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:645
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:18028
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:777
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:578
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:680
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12663
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7567
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9641
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9304
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13953
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:15166
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:580
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17554
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18390
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:871
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:740
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:869
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1611
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:887
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12467
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:157
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4455
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3662
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:687
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:845
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1514
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:596
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:774
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:810
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7915
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:438
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:676
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:599
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4615
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1298
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6365
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10749
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:668
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:882
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3538
Unused
@ Unused
Definition: TrackUnit.h:65
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:601
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:631
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1297
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:719
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18864
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2857
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:784
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:222
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19059
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:574
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9471
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1669
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1512
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1598
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:204
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:932
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:711
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:436
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:834
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3262
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15539
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:791
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:683
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8367
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12729
Simple
@ Simple
Definition: TrackUnit.h:65
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:784
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:808
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2873
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:713
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1020
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18138
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:789
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:833
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1365
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:720
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12980
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3859
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1734
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:609
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5773
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:684
TTrain
Definition: TrainUnit.h:302
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:376
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13824
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:152
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11379
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:575
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:570
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:856
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:626
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7582
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:65
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:804
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18499
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:870
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7328
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:148
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:935
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:148
TTrack::Raising
@ Raising
Definition: TrackUnit.h:607
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:642
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:568
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10365
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1516
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1480
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:712
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:684
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:580
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:786
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:775
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:729
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1374
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6025
End
@ End
Definition: TrackUnit.h:75
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1518
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:682
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:857
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:618
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8721
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:878
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:918
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:563
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10474
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1033
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:299
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:814
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:726
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:792
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:592
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:928
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:124
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:737
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:772
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3833
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1004
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:848
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1005
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:226
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:715
SignalPost
@ SignalPost
Definition: TrackUnit.h:65
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9436
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1014
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17542
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:502
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:792
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1635
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:806
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:841
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7596
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:667
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6774
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:643
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:224
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:699
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8760
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:921
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:831
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17527
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:770
Concourse
@ Concourse
Definition: TrackUnit.h:66
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:671
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:801
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:815
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:74
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13594
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13331
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:728
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:901
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:64
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4540
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1878
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:828
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:843
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:608
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:818
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:430
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:766
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:93
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:830
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:589
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:10952
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:18343
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4774
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:157
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1897
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:774
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:688
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:803
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:939
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:742
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:558
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:600
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:734
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:849
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:464
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:652
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11197
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:18965
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:586
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1031
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:625
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2841
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:724
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1524
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7553
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14770
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7209
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8557
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7288
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:681
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:735
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5684
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:689
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:674
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:315
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:680
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1300
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:848
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:817
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:816
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13068
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:780
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:881
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12203
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1636
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1688
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:45
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:919
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:602
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12696
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:666
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17314
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3639
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13284
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11240
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10615
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1780
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:778
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:913
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:577
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5867
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12516
Under
@ Under
Definition: TrackUnit.h:75
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16824
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:801
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:710
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:622
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2896
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11391
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11711
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:885
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:427
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:134
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10509
Lead
@ Lead
Definition: TrackUnit.h:75
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5732
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1814
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13532
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:5944
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:867
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5524
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6346
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:85
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1329
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9232
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:593
TTrack::Up
@ Up
Definition: TrackUnit.h:607
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:877
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:803
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:581
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10488
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:938
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1474
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8524
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1629
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:738
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:200
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17381
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1618
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:795
Crossover
@ Crossover
Definition: TrackUnit.h:65
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6232
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:805
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:637
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8470
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:797
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7237
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9899
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:75
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:568
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:586
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:772
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17831
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:152
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1548
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12566
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11136
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4624
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:566
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10460
TGraphicElement::Width
int Width
Definition: TrackUnit.h:434
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18739
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:18949
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17657
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:778
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:777
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:584
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:656
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:785
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14362
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:654
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4141
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2359
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:687
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9372
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12334
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:603
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:876
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:940
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5708
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:19032
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:582
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1516
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:925
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:783
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1505
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:842
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6935
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:744
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1044
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1046
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7768
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17473
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:655
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7310
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:799
Erase
@ Erase
Definition: TrackUnit.h:66
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:846
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5329
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:801
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1668
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:826
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:873
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:590
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13354
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:614
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11048
Parapet
@ Parapet
Definition: TrackUnit.h:66
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17500
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:800
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1008
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:269
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9041
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17446
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:866
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:801
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:18366
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:605
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:930
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:776
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:798
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:146
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:821
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1049
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:721
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:813
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:14765
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:838
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:136
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:202
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11268
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12261
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1278
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17409
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:611
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:746
TTrack
Definition: TrackUnit.h:544
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1337
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:848
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1368
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18515
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1605
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8069
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:635
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:584
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:855
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:665
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:741
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:864
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:127
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:820
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:700
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:200
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:18006
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:208
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2976
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8943
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:924
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6126
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2111
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:583
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:739
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:157
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:163
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:859
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:784
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2577
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:198
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1603
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7732
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12049
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12827
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:582
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1480
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10397
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8433
IDInt
Definition: TrackUnit.h:493
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2383
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:588
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:19000
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:612
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:793
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4428
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10147
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5074
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:144
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:850
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:787
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:836
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:436
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:19097
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1126
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9155
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:566
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:96
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7679
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1279
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:152
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:901
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13137
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:762
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:745
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:646
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:206
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:862
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14158
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1673
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:129
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:782
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7647
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:628
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:823
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:796
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:730
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:146
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:883
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:769
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1491
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:853
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1609
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:850
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1619
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4696
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:585
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:8981
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:690
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15345
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1307
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:731
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:430
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13460
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:827
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1285
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13235
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:150
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:717
Points
@ Points
Definition: TrackUnit.h:65
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:738
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:18079
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:868
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9830
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11119
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:597
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:835
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4163
Trail
@ Trail
Definition: TrackUnit.h:75
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17358
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9214
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:16943
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:776
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1850
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:819
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16761
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:832
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:662
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:740
Continuation
@ Continuation
Definition: TrackUnit.h:65
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1040
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7526
GraphicUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3739
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5964
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9261
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:867
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:875
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:883
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12092
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:572
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:837
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:767
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:872
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:430
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14806
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1029
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3356
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:434
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:888
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1508
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:87
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:703
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:657
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:723
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1667
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:926
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:263
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:743
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:851
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19179
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13032
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1018
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:781
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1482
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1022
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:768
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:630
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:877
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4681
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:886
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:17977
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1700
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8571
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:713
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:691
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:591
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:788
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:667
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10906
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:825
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:702
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1339
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:19016
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:576
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1860
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4666
Connection
@ Connection
Definition: TrackUnit.h:75
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3716
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1675
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9493
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1009
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:747
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16574
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11910
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:721
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:824
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8497
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:874
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1027
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18288
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18244
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7008
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:561
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10777
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:706
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:865
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:717
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1366
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:898
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5752
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:858
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:722
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:430
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:752
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9953
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:568
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:719
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:730
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17514
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4806
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:802
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2752
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:689
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7607
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3118
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:854
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:131
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:879
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16732
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:624
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13724
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:313
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:750
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:604
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:688
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:628
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1279
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:649
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:659
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:914
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:639
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11470
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:430
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:933
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:99
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1478
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:195
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8620
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:812
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1758
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8802
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:640
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:586
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:707
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13431
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:18984
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:140
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:606
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1336
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4259
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:794
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4557
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7470
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1955
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1035
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6272
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1006
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:709
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:65
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:839
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:641
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7265
Platform
@ Platform
Definition: TrackUnit.h:65
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1368
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:208
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:661
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:884
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:756
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:686
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4582
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:770
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1613
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1042
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:779
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:936
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8020
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:679
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1292
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:809
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:844
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9410
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1016
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:768
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11013
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1765
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:829
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:638
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1480
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15766
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7453
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:796
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:148
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:794
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:692
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1482
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:611
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6289
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:723
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3616
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:771
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:657
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TTrack::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:760
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:579
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:801
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:736
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10939
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:788
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:880
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:848
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:148
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:40
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:675
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:927
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:299
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:708
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:620
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:727
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:581
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:89
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16140
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:682
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:799
RouteCall
@ RouteCall
Definition: TrackUnit.h:1285
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11404
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:860
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:606
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:75
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:665
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18560
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:261
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:607
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:594
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10968
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10229
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:670
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:198
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:790
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:929
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6190
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:157
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:937
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:728
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11416
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1341
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:142
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1530
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:852
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:736
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:822
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:707
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:568
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:629
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10220
Bridge
@ Bridge
Definition: TrackUnit.h:65
TTrack::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:758
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:863
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1279
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:811
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:75
Buffers
@ Buffers
Definition: TrackUnit.h:65
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16490
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:704
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:75
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11428
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4494
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11351
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:847